import sys
import asyncio
import re
import json
import logging
import gzip
import threading
import time
import urllib.parse
import codecs
import binascii
import hashlib
import random
import io
import string
import subprocess
import zipfile
import signal
import queue
import _thread
import html
import os
from bs4 import BeautifulSoup
from io import BytesIO
from pathlib import Path
from urllib.parse import urlencode
from datetime import datetime
from collections import namedtuple
from contextlib import contextmanager
from unittest.mock import patch
from google.protobuf import json_format
from protobuf_inspector.types import StandardParser
from PyQt5.QtWidgets import (
    QApplication,
    QMainWindow,
    QVBoxLayout,
    QWidget,
    QPushButton,
    QHBoxLayout,
    QLineEdit,
    QGraphicsView,
    QGraphicsScene,
    QGraphicsPixmapItem,
    QDialog,
    QListWidgetItem,
    QListWidget,
    QLabel,
    QProgressBar,
    QCheckBox,
    QMessageBox,
    QListView
    
)
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent, QMediaPlaylist
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtCore import (
    QUrl,
    pyqtSignal,
    Qt,
    QTimer,
    QBuffer,
    QIODevice,
    QThread,
    QObject,
    pyqtSlot,
    QEvent,
    QSize,
    QPoint
)
from PyQt5.QtGui import QColor, QPixmap, QFont, QImage, QIcon, QStandardItemModel, QStandardItem, QTextDocument, QTextCursor
from PyQt5 import QtWidgets
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings, QWebEnginePage
from PyQt5.QtWebChannel import QWebChannel
from PyQt5 import QtCore
import qrcode
import requests
import websocket
import execjs
import betterproto
from src import a_bus
from ui import Ui_Form
from dialog1 import Ui_Dialog
from dialog2 import Ui_Dialog2
from dialog3 import Ui_Dialog3
from dialog4 import Ui_Dialog4
from dialog5 import Ui_Dialog5
from proto.dy_pb2 import PushFrame
from proto.dy_pb2 import Response
from proto.dy_pb2 import MatchAgainstScoreMessage
from proto.dy_pb2 import LikeMessage
from proto.dy_pb2 import MemberMessage
from proto.dy_pb2 import GiftMessage
from proto.dy_pb2 import ChatMessage
from proto.dy_pb2 import SocialMessage
from proto.dy_pb2 import RoomUserSeqMessage
from proto.dy_pb2 import UpdateFanTicketMessage
from proto.dy_pb2 import CommonTextMessage
from proto.dy_pb2 import ProductChangeMessage
from proto.dy_pb2 import LinkMessage
from proto.dy_pb2 import LinkMicBattle
from proto.dy_pb2 import LinkMicBattleFinish
from proto.dy_pb2 import LinkmicTeamfightScoreMessage
from proto.dy_pb2 import LinkmicTeamfightMessage
from proto.dy_pb2 import LinkmicOrderSingMessage
from proto.dy_pb2 import LinkmicOrderSingScoreMessage
from proto.dy_pb2 import LinkmicProfitMessage
from proto.dy_pb2 import LinkMicMethod
from proto.dy_pb2 import LinkMicArmies
from proto.dy_pb2 import GuestBattleMessage
from proto.dy_pb2 import GuestBattleScoreMessage
from proto.dy_pb2 import LinkSettingNotifyMessage
#from encode_video import process_video

RoomInfo = namedtuple("RoomInfo", ["room_id", "m3u8_adr", "author_name"])


class MainWindow(QtWidgets.QWidget):
    new_enter_message = pyqtSignal(str)
    new_update_gift = pyqtSignal(str)
    new_update_chat = pyqtSignal(str)
    new_update_info = pyqtSignal(str, str)
    new_update_pic = pyqtSignal(str, dict)
    # new_update_qrcode = pyqtSignal(object)
    update_myinfo_signal = pyqtSignal(str)
    # gift_list_single = pyqtSignal(str)

    #   new_query_login_info = pyqtSignal()
    start_live_signal = pyqtSignal(str)

    def __init__(self):
        super().__init__()

        self.ui = Ui_Form()
        self.ui.setupUi(self)
        self.widget = self.ui.widget_2
        self.player = QMediaPlayer(self)
        self.playlist = QMediaPlaylist(self.player)
        # self.video_widget.setAspectRatioMode(1)  # 设置保持宽高比
        self.widget.setStyleSheet("background-color: black;")
        self.player.setPlaylist(self.playlist)
        self.player.setVideoOutput(self.widget)
        
        self._textEdit = self.ui.textEdit

        self.liveRoomId = ""
        self.user_unique_id = ""
        self.wss_signature_vaule = ""
        self.ttwid = ""
        self.web_rid = ""
        self.adr = ""
        self.start_time = None
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)

        self.url_queue = queue.Queue()
        self.gift_effect_playing = False

        # 登录用户cookie
        self.user_cookies = None
        self.author_name = ""
        session = ""

        ##获取qrcode相关
        self.session = session
        self.login_url = "https://sso.douyin.com/get_qrcode/"
        self.check_login_url = "https://sso.douyin.com/check_qrconnect/"
        self.max_retries = 3  # 最大重试次数
        self.retry_delay = 2  # 初始重试延迟时间（秒）

        self.thread_wss = None
        self.thread_wss_info = None

        self.thread_auto_like = None

        self.mediator = DataMediator()
        self.mediator_1 = DataMediator_1()

        # self.ui.label_31.setText("12345678")

        ##进入直播间相关

        ##礼物特效

        self.gift_effect = self.ui.widget_3

        self.gift_effect.setWindowFlags(
            Qt.Tool | Qt.FramelessWindowHint
        )  # 定义工具窗口 + 隐藏边框

        self.gift_effect.setAttribute(Qt.WA_TranslucentBackground, True)  # 透明相关
        self.gift_effect.setStyleSheet("background-color: transparent;")

        self.gift_effect.page().settings().setAttribute(
            QWebEngineSettings.ShowScrollBars, False
        )  # 隐藏滑动
        self.gift_effect.page().setBackgroundColor(Qt.transparent)

        channel = QWebChannel(self.gift_effect.page())
        self.gift_effect.page().setWebChannel(channel)
        channel.registerObject("mainWindow", self)

        self.position_tracker = WindowPositionTracker(self.widget)
        self.position_tracker.position_changed.connect(self.move_gift_effect)

        # 为MainWindow安装事件过滤器
        self.installEventFilter(self)

        # self.browser = QWebEngineView()
        # self.browser.hide

        # channel = QWebChannel(self.browser.page())
        # self.browser.page().setWebChannel(channel)
        # channel.registerObject("mainWindow", self)
        

        # 设置lineEdit的提示词

        self.ui.lineEdit_2.setPlaceholderText("请输入作者ID/直播间ID")
        self.ui.pushButton.clicked.connect(self.query_info)  # 查询按钮点击
        self.ui.pushButton_2.clicked.connect(self.send_msg)  # send_msg
        self.ui.pushButton_3.clicked.connect(self.creat_qrcode)  # 刷新二维码点击
        self.ui.pushButton_4.clicked.connect(self.enter)  # 进入直播间
        self.ui.pushButton_5.clicked.connect(self.leave)  # 离开直播间
        self.ui.pushButton_6.clicked.connect(self.start_auto_link)
        self.ui.pushButton_7.clicked.connect(self.clear_msg)  # 清除消息
        self.ui.pushButton_8.clicked.connect(self.toggle_play_pause)  # 视频切换
        # self.ui.pushButton_8.clicked.connect(self.play_gift_effect)
        self.ui.pushButton_9.clicked.connect(self.show_dialog1)
        self.ui.pushButton_10.clicked.connect(self.show_dialog2)
        self.ui.pushButton_11.clicked.connect(self.show_dialog3)
        self.ui.pushButton_12.clicked.connect(self.show_dialog4)
        self.ui.pushButton_13.clicked.connect(self.toggle_muted)
        self.ui.pushButton_14.clicked.connect(self.live_separate_window)
        self.ui.pushButton_15.clicked.connect(self.show_dialog5)
        self.ui.toolButton.clicked.connect(self.open_emoji_selector)
        self.start_live_signal.connect(self.live_stream)  # 开启直播视频信号
        self.update_myinfo_signal.connect(self.update_myinfo)
        # self.gift_list_single.connect(self._gift_list)
        self.ui.checkBox.clicked.connect(self.start_auto_reply_message_thread)

        self.ui.textBrowser_2.setAcceptRichText(True)
        self.ui.textBrowser_2.setOpenExternalLinks(True)
        self.ui.textBrowser_2.setOpenLinks(True)

        # 背景颜色
        self.ui.textBrowser.setStyleSheet(
            "QTextBrowser { background-color: #808080; }"
        )
        
        #splitter自定义
        self.ui.splitter.setSizes([400, 100, 100])

    def query_info(self):
        # self.onClose(self)
        # self.ui.textBrowser.clear()
        # self.ui.textBrowser_2.clear()
        # self.ui.textBrowser_3.clear()
        # self.widget_1.setStyleSheet("background-color: transparent;")
        # self.widget_1.hide()
        # self.ui.textBrowser.clear()
        # self.ui.textBrowser_2.clear()
        # self.ui.textBrowser_3.clear()
        self.clear_msg()
        input_text = self.ui.lineEdit_2.text()
        print("输入的查询文本:", input_text)
        if input_text:
            url = f"https://live.douyin.com/{input_text}"
            print("构建的URL:", url)
            try:
                data = self.parseLiveRoomUrl(url)
                if isinstance(data, RoomInfo):
                    self.liveRoomId = data.room_id
                    m3u8_adr = data.m3u8_adr
                    self.adr = m3u8_adr
                    # print(self.adr)
                    self.author_name = data.author_name
                    self.ui.label_6.setText(self.author_name)
                    self.ui.label_7.setText(self.liveRoomId)
                    if self.liveRoomId:
                        self.player.stop()  # 暂停播放
                        self.playlist.clear()  # 清空播放列表
                        self.start_live_signal.emit(m3u8_adr)
                        # self.start_wss()          #开启wss
                        self.stop_wss()
                        # self._wss()
                        self.query_wss_signature()
                        self.close_wss_info_thread()
                        self.start_wss_info_thread()
                        self.loadcookies()
                        # self.start_auto_reply_message_thread()
                else:
                    logging.error("返回的数据不是预期的RoomInfo类型")
            except Exception as e:
                logging.error(f"获取信息时发生未知错误: {e}")
        else:
            logging.error("请先输入有效信息")

    def _roominfo(self, message_1, message_2):  # 房间信息 显示栏
        self.ui.label_8.setText(message_2)  # 场观
        self.ui.label_9.setText(message_1)  # 在线

        # 更新聊天界面

    def _chat(self, message):  # 聊天界面 显示栏
        # current_time = datetime.now().strftime('%H:%M:%S')
        current_text = self.ui.textBrowser.toPlainText()
        # full_message = f'[{current_time}] {message}'
        # full_message = f'<span style="color: red;">[{current_time}] {message}</span>'
        self.ui.textBrowser.append(message)

        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "chat_message_count"):
            self.chat_message_count = 0
        self.chat_message_count += 1
        if self.chat_message_count > 1000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[900:]
            # 更新文本浏览器的内容
            self.ui.textBrowser.setPlainText("\n".join(lines))
            # 重置计数
            self.chat_message_count = len(lines)

        # 更新进入人员

    def _enter(self, message):  # 人员进入 显示栏
        # 获取当前时间
        #current_time = datetime.now().strftime("%H:%M:%S")
        # 将时间和消息组合
        # print(message)
        #full_message = f"[{current_time}] {message}"
        self.ui.textBrowser_3.append(message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_3.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "enter_message_count"):
            self.enter_message_count = 0
        self.enter_message_count += 1
        if self.enter_message_count > 1000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_3.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[900:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_3.setPlainText("\n".join(lines))
            # 重置计数
            self.enter_message_count = len(lines)

        # 更新礼物/点赞/关注界面

    def _gift(self, message):  # 礼物 点赞 关注 显示栏
        #current_time = datetime.now().strftime("%H:%M:%S")
        #full_message = f"[{current_time}] {message}"
        self.ui.textBrowser_2.append(message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_2.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "gift_message_count"):
            self.gift_message_count = 0
        self.gift_message_count += 1
        if self.gift_message_count > 1000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_2.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[900:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_2.setPlainText("\n".join(lines))
            # 重置计数
            self.gift_message_count = len(lines)

        # 更新礼物榜单

    def _gift_list(self, message):  # 自定义礼物 显示栏
        current_time = datetime.now().strftime("%H:%M:%S")
        full_message = f'<span style="display:inline-block; vertical-align:middle;">[{current_time}]</span>{message}'
        self.ui.textBrowser_6.append(full_message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_6.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "diygift_message_count"):
            self.diygift_message_count = 0
        self.diygift_message_count += 1
        if self.diygift_message_count > 30000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_6.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[29000:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_6.setPlainText("\n".join(lines))
            # 重置计数
            self.diygift_message_count = len(lines)

    # 更新高等级用户榜单
    def _user_list(self, message):  # 自定义高等级用户 显示栏
        current_time = datetime.now().strftime("%H:%M:%S")
        # <span style="display:inline-block; vertical-align:middle;">[{current_time}]</span>
        full_message = f'<span style="display:inline-block; vertical-align:middle;">[{current_time}]</span>{message}'
        self.ui.textBrowser_7.append(full_message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_7.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "diyuser_message_count"):
            self.diyuser_message_count = 0
        self.diyuser_message_count += 1
        if self.diyuser_message_count > 3000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_7.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[2900:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_7.setPlainText("\n".join(lines))
            # 重置计数
            self.diyuser_message_count = len(lines)

    # def _pk_list(self, msg):
    # # # print(msg)
    # # # print("运行到这里了！")
    # # # if msg == 2:
    # # self.ui.progressBar.setProperty("visible", True)
    # # self.ui.progressBar.setStyleSheet("QProgressBar { opacity: 100; }")
    # # self.ui.label_22.setProperty("visible", True)
    # # self.ui.label_24.setProperty("visible", True)
    # # self.ui.lcdNumber.setProperty("visible", True)
    # # # elif msg == 4:

    def _pk_score(self, msg):
        print("运行到这里了！_pk_score")
        # self.ui.label_31.raise_()
        # self.ui.progressBar.setProperty("visible", True)
        # self.ui.progressBar.setStyleSheet("QProgressBar { opacity: 100; }")
        # self.ui.label_22.setProperty("visible", True)
        # self.ui.label_24.setProperty("visible", True)
        # self.ui.lcdNumber.setProperty("visible", True)
        # play_count = len(msg)
        # nickname_list = list(msg.keys())
        # self.ui.label_22.setText(msg[nickname_list[1]])
        # self.ui.label_24.setText(msg[nickname_list[0]])

    def _reply_info(self, message):  # 自动回复 消息显示栏
        current_time = datetime.now().strftime("%H:%M:%S")
        # <span style="display:inline-block; vertical-align:middle;">[{current_time}]</span>
        full_message = f'<span style="display:inline-block; vertical-align:middle;">[{current_time}]</span>{message}'
        self.ui.textBrowser_5.append(full_message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_5.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "reply_message_count"):
            self.reply_message_count = 0
        self.reply_message_count += 1
        if self.reply_message_count > 3000:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_5.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[2900:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_5.setPlainText("\n".join(lines))
            # 重置计数
            self.reply_message_count = len(lines)

    def enter(self):  ##进入直播间
        # url = 'https://live.douyin.com/webcast/room/web/enter/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&language=zh-CN&enter_from=web_homepage_follow&cookie_enabled=true&screen_width=2560&screen_height=1440&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=130.0.0.0&web_rid=' + self.web_rid + '&room_id_str=' + self.liveRoomId + '&enter_source=&is_need_double_stream=false&insert_task_id=&live_reason='
        url = "https://live.douyin.com/webcast/room/web/enter/"
        params = {
            "aid": "6383",
            "app_name": "douyin_web",
            "live_id": "1",
            "device_platform": "web",
            "language": "zh-CN",
            "enter_from": "web_search",
            "cookie_enabled": "true",
            "screen_width": "2560",
            "screen_height": "1440",
            "browser_language": "zh-CN",
            "browser_platform": "Win32",
            "browser_name": "Chrome",
            "browser_version": "130.0.0.0",
            "web_rid": self.web_rid,
            "room_id_str": self.liveRoomId,
            "enter_source": "",
            "is_need_double_stream": "false",
            "insert_task_id": "0",
            "live_reason": "",
            "msToken": "pm-tC_vHvChX2W8OzXOIQ2bUB9ro1_YKB3cM-Mc3LypPlnoGpd9Lrk6JiVvqGhKTNf-WlHVm6C5yQbkVcFvsMbOVfxxAaO9wWFrYIGGJZgciXsyxQbJP9jbJYLgDRReVM-TtQASocdMyXqGwkSiqlOmebH6P-OMqd4Co49g8IESc",
        }
        headers = {
            "accept": "application/json, text/plain, */*",
            #'cookie': self.user_cookies,
            "accept-language": "zh-CN,zh;q=0.9",
            "origin": "https://www.douyin.com",
            "priority": "u=1, i",
            "referer": "https://www.douyin.com/",
            "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "Windows",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
        }
        user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        uri = urlencode(params)
        bc = a_bus.BogusCreator()  # 调用实例
        bogus_request = bc.create_bogus(uri, user_agent)
        params["a_bogus"] = bogus_request
        response = requests.get(
            url, params=params, headers=headers, cookies=self.user_cookies
        )
        if response.status_code == 200:
            print("进入成功")
            message = f"id:XXX 进入  直播间 成功"  # {self.author_name}
            # self.update_myinfo.emit(message)   #通过信号把数据返回给主函数(界面信息)

        else:
            print("进入失败")
            message = f"id:XXX 进入 直播间 失败"

    def leave(self):  ##离开直播间
        if self.liveRoomId != "" and self.user_cookies is not None:
            url = "https://live.douyin.com/webcast/web/leave/"
            params = {
                "aid": "6383",
                "app_name": "douyin_web",
                "live_id": "1",
                "device_platform": "web",
                "language": "zh-CN",
                "enter_from": "web_search",
                "cookie_enabled": "true",
                "screen_width": "2560",
                "screen_height": "1440",
                "browser_language": "zh-CN",
                "browser_platform": "Win32",
                "browser_name": "Chrome",
                "browser_version": "130.0.0.0",
                "room_id": self.liveRoomId,
                "leave_source": "WEB_INITIATIVE",
                "verifyFp": "verify_m26ah04p_WnwFbrYK_QblP_4g8Q_8l6Q_B26sglIK7amn",
                "fp": "verify_m26ah04p_WnwFbrYK_QblP_4g8Q_8l6Q_B26sglIK7amn",
                "msToken": "LUeJuj53n54w74EeFSR6lknlftrWAQLWs7gMfYwKva8dKQ5cf-lPHXOUHHbE77PorZweK9ICiSVWupEq_P2KfFPqu9G6tQJmJ33MvmGJmejWn5rFO8RJCyBbUYZkZbptNZaGoPRq-k0PQCF_TaBF6GiUh7vxf0q8gRXUYUO-hB4diH47c6bO6Q%3D%3D",
            }
            headers = {
                "accept": "application/json, text/plain, */*",
                # 'cookie': self.user_cookies,
                "accept-language": "zh-CN,zh;q=0.9",
                "origin": "https://www.douyin.com",
                "priority": "u=1, i",
                "referer": "https://www.douyin.com/",
                "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
                "sec-ch-ua-mobile": "?0",
                "sec-ch-ua-platform": "Windows",
                "sec-fetch-dest": "empty",
                "sec-fetch-mode": "cors",
                "sec-fetch-site": "same-site",
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
            }
            # print(headers)
            user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
            uri = urlencode(params)
            bc = a_bus.BogusCreator()  # 调用实例
            bogus_request = bc.create_bogus(uri, user_agent)
            params["a_bogus"] = bogus_request
            response = requests.get(
                url, params=params, headers=headers, cookies=self.user_cookies
            )
            if response.status_code == 200:
                message = f"id:XXX 退出 {self.author_name} 直播间 成功"
                # self.update_myinfo.emit(message)
            else:
                message = f"id:XXX 退出 {self.author_name} 直播间 失败"

    def update_myinfo(self, msg):  ## 自定义消息栏
        current_time = datetime.now().strftime("%H:%M:%S")
        full_message = f"[{current_time}] {msg}"
        self.ui.textBrowser_4.append(full_message)
        # 获取垂直滚动条
        scroll_bar = self.ui.textBrowser_4.verticalScrollBar()
        # 设置滚动条到最大位置，即滚动到最新消息
        scroll_bar.setValue(scroll_bar.maximum())
        if not hasattr(self, "chat_message_count"):
            self.myinfo_count = 0
        self.myinfo_count += 1
        if self.myinfo_count > 500:
            # 获取当前文本浏览器中的所有行
            lines = self.ui.textBrowser_4.toPlainText().split("\n")
            # 删除最开始的500行数据
            lines = lines[300:]
            # 更新文本浏览器的内容
            self.ui.textBrowser_4.setPlainText("\n".join(lines))
            # 重置计数
            self.myinfo_count = len(lines)

    def clear_msg(self):  ## 清屏
        self.ui.textBrowser.clear()
        self.ui.textBrowser_2.clear()
        self.ui.textBrowser_3.clear()
        self.ui.textBrowser_4.clear()
        self.ui.textBrowser_5.clear()
        self.ui.textBrowser_6.clear()
        self.ui.textBrowser_7.clear()
    
    def open_emoji_selector(self):
        # 获取当前脚本所在目录
        script_dir = os.path.dirname(__file__)
        # 构建表情图片文件夹的绝对路径，假设emoji文件夹就在脚本所在目录下
        emoji_folder = os.path.join(script_dir, 'src/pic/emoji')
        emoji_images = list(Path(emoji_folder).glob('*.png'))
        dialog = EmojiSelectorDialog(emoji_images, self)

        if dialog.exec_():  # 如果对话框被接受（例如点击了OK）
            selected_index = dialog.selected_index
            if not emoji_images:
                print("表情列表为空，请检查表情包文件夹路径及文件格式是否正确")
                return
            elif not (0 <= selected_index < len(emoji_images)):
                print(f"无效的表情索引，索引值为 {selected_index}，合法范围应该是 0 到 {len(emoji_images) - 1}")
                return
            try:
                selected_image_path = emoji_images[selected_index]
                file_name = Path(selected_image_path).name  # 获取文件名（不含路径）
                display_text = f'<img src="{emoji_folder}/{file_name}" alt="{file_name}" width="18" height="18" vertical-align: bottom />'
                #在样式表中添加对应的类样式定义
                # self.ui.textEdit.document().setDefaultStyleSheet("""
                # QTextEdit.emoji-img {
                        # width: 5px;
                        # height: 5px;
                        # display: inline-block;
                    # }
                # """)
                cursor = QTextCursor(self.ui.textEdit.document())
                # 获取当前光标位置
                cursor.setPosition(self.ui.textEdit.textCursor().position())
                cursor.insertHtml(display_text)
            except Exception as e:
                print(f"在将表情相关信息插入输入框时出现错误: {e}")
        
        
    def send_msg(self):  ##发送消息
        input_html = self.ui.textEdit.toHtml()
        soup = BeautifulSoup(input_html, 'lxml')
        result = ''
        #print(input_html)
        try:
            for p in soup.find_all('p'):
                # 遍历p标签内的所有子节点
                for child in p.children:
                    if child.name == 'img':  # 如果是img标签
                        # 提取alt属性中的文本，去除文件扩展名
                        alt_text = child.get('alt', '').rsplit('.', 1)[0]
                        result += f"{alt_text}"
                    elif isinstance(child, str):  # 如果是字符串，即纯文本
                        result += child.strip()
        except Exception as e:
            print("正则错误:", e)

        input_text = result
        #print(f'打印结果: {input_text}')
        url = "https://live.douyin.com/webcast/room/chat/"
        params = {
            "aid": "6383",
            "app_name": "douyin_web",
            "live_id": "1",
            "device_platform": "web",
            "language": "zh-CN",
            "enter_from": "web_search",
            "cookie_enabled": "true",
            "screen_width": "2560",
            "screen_height": "1440",
            "browser_language": "zh-CN",
            "browser_platform": "Win32",
            "browser_name": "Chrome",
            "browser_version": "130.0.0.0",
            "room_id": self.liveRoomId,
            "content": input_text,
            "type": "0",
        }

        headers = {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9",
            "referer": "https://live.douyin.com/",
            "priority": "u=1, i",
            "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": '"Windows"',
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-origin",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
        }

        uri = urlencode(params)
        # print(uri)
        user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        # 创建 BogusCreator 实例
        bc = a_bus.BogusCreator()
        # 使用提供的 uri 和 user_agent 创建 bogus 请求
        bogus_request = bc.create_bogus(uri, user_agent)
        params["a_bogus"] = bogus_request
        # print(self.user_cookies)
        response = requests.get(
            url, params=params, headers=headers, cookies=self.user_cookies
        )

        # print(response.text)
        if response.status_code == 200:
            message = f"【发送成功】 {input_text}"
            # self.new_update_myinfo.emit(message)
            print(f"已发送： {input_text}")
        else:
            message = f"【发送失败】 {input_text}"
            # self.new_update_myinfo.emit(message)
            print("发送失败")

    def loadcookies(self):  # 读取本地cookie
        if self.user_cookies is  None:
            try:
                with open("cookies.json", "r") as f:
                    self.user_cookies = json.load(f)
                    self.update_myinfo_signal.emit("导入本地cookie成功")
            except FileNotFoundError:
                print("Cookie file not found.")
            except json.JSONDecodeError:
                print("Error decoding JSON in the cookie file.")

    ###视频播放###
    def live_stream(self, adr):  ## 直播视频 相关

        # print(url)
        try:

            # print(adr)

            # m3u8_url = urllib.parse.unquote(url)
            # while '\\u0026' in m3u8_url:
            # m3u8_url = urllib.parse.unquote(m3u8_url)
            # #m3u8_url = m3u8_url
            # print(m3u8_url)
            media_content = QMediaContent(QUrl(adr))
            # print(adr)
            self.playlist.addMedia(media_content)
            self.player.play()
            self.player.setMuted(False)
            # width = int(self.width() * 9 / 16)
            # self.video_widget.setFixedSize(width, self.height())
        except Exception as e:
            print("Error loading media:", e)

    def live_separate_window(self):
        print(self.adr)
        self.player.stop()
        self.playlist.clear()
        self.player.setMuted(True)
        self.media_window = MediaWindow(self.adr)
        #self.media_window.closeEvent = self.close_video_window
        #self.media_window.show()
        # 创建垂直布局
        # layout = QVBoxLayout()
        # self._separate_window = QVideoWidget(self)
        # self._separate_window.setWindowFlags(Qt.Tool)
        # self._separate_window.resize(720, 1280)        
        # self.player_1 = QMediaPlayer(self)
        # self.playlist = QMediaPlaylist(self.player)
        # self.player_1.setPlaylist(self.playlist)
        # self.player_1.setVideoOutput(self._separate_window)

        # media_content = QMediaContent(QUrl(self.adr))
        # self.playlist.addMedia(media_content)

        # layout.addWidget(self._separate_window)
        # self.setLayout(layout)
        # self._separate_window.closeEvent = self.close_video_window 
        # # 连接mediaStatusChanged信号，用于在视频状态变化时调整视频显示大小
        # # self.player.mediaStatusChanged.connect(self.adjust_video_size)
        # self._separate_window.show()
        
        #self.player_1.play()
    def close_video_window(self, event):
        self.player_1.stop()
        del self._separate_window         
        event.accept() 

    def closeEvent(self, event):  # 已完成 /待添加
        self.mediaPlayer.stop()
        event.accept()

    def toggle_play_pause(self):  # 播放/暂停
        if self.player.state() == QMediaPlayer.PlayingState:
            self.player.pause()
            self.ui.pushButton_8.setStyleSheet("color: red;")

        else:
            self.player.play()
            self.ui.pushButton_8.setStyleSheet("color: black;")

    def toggle_muted(self):  ##静音
        self.player.setMuted(not self.player.isMuted())
        if self.player.isMuted():
            self.ui.pushButton_13.setStyleSheet("color: red;")  # 设置文字颜色为红色
            # self.mute_status_label.setText("静音")
        else:
            self.ui.pushButton_13.setStyleSheet("color: black;")  # 设置文字颜色为黑色

    def creat_qrcode(self):  ##登录二维码 相关
        self.thread_qrcode = QR_code()
        self.thread_qrcode.qrcode_image_signal.connect(
            self.display_qrcode
        )  # 传送二维码信号
        self.thread_qrcode.close_QR_code_QThread_signal.connect(
            self.close_qrcode_QThread
        )  # 关闭线程新号
        self.thread_qrcode.cookies_signal.connect(self.save_cookies)
        self.update_myinfo_signal.emit("获取登录二维码")
        self.thread_qrcode.start()

    def close_qrcode_QThread(self):  ##关闭 二维码进程
        if self.thread_qrcode:
            self.thread_qrcode.stop_thread = True
            self.thread_qrcode.quit()
            self.thread_qrcode.wait()
            self.update_myinfo_signal.emit("二维码线程关闭")
        # print("关闭线程")

    def display_qrcode(self, img):  ##显示二维码
        self.ui.label_18.setPixmap(img)

    def save_cookies(self, cookie):  # 已完成  保存扫码用户的cookie
        self.user_cookies = cookie
        self.user_cookies.update({"ttwid": f"{self.ttwid}"})
        with open("cookies.json", "w") as f:
            json.dump(self.user_cookies, f)
        self.update_myinfo_signal.emit("保存cookie成功")

    def query_wss_signature(self):
        print(self.liveRoomId)
        print(self.user_unique_id)
        print("运行到generateSignature")
        # self.browser = QWebEngineView()
        # self.browser.hide
        self.browser = QWebEngineView()
        self.browser.hide

        channel = QWebChannel(self.browser.page())
        self.browser.page().setWebChannel(channel)
        channel.registerObject("mainWindow", self)

        generateSignature_html = f"""
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test Signature</title>
    <script src="js/qwebchannel.js"></script>
    <script src="js/byted_acrawler.js"></script>
</head>    
<body data-roomId="{self.liveRoomId}" data-uniqueId="{self.user_unique_id}">
    <script src="js/creatSignature.js"></script>
</body>
</html>
"""

        # 创建一个包含视频的本地 HTML 文件
        if not os.path.exists('src'):
            os.makedirs('src')
        with open("src/generateSignature_html.html", "w") as f:
            f.write(generateSignature_html)

        self.browser.load(
            QUrl.fromLocalFile(os.path.abspath("src/generateSignature_html.html"))
        )

    @pyqtSlot(str)
    def pyqt_slot_data(self, vaule):  # 返回wss_signature 启动_WSS进程
        print(vaule)
        if vaule != "":
            self.wss_signature_vaule = vaule
            self.browser.close()
            del self.browser
            self._wss()

    def _wss(self):
        self.thread_wss = start_wss(
            self.liveRoomId,
            self.user_unique_id,
            self.wss_signature_vaule,
            self.ttwid,
            self.mediator,
        )
        self.thread_wss.chat_single.connect(
            self._chat, Qt.ConnectionType.QueuedConnection
        )  # 聊天信号
        self.thread_wss.gift_single.connect(
            self._gift, Qt.ConnectionType.QueuedConnection
        )  # 礼物信号
        self.thread_wss.like_single.connect(
            self._gift, Qt.ConnectionType.QueuedConnection
        )  # 点赞信号
        self.thread_wss.social_single.connect(
            self._gift, Qt.ConnectionType.QueuedConnection
        )  # 关注信号
        self.thread_wss.enter_single.connect(
            self._enter, Qt.ConnectionType.QueuedConnection
        )  # 进入信号
        self.thread_wss.roominfo_single.connect(
            self._roominfo, Qt.ConnectionType.QueuedConnection
        )  # 房间信息信号
        # self.thread_wss.total_info_single.connect(self.display_gift_user_reply, Qt.ConnectionType.QueuedConnection)  #传输字典
        self.update_myinfo_signal.emit("准备启动弹幕线程")
        self.thread_wss.start()

    def stop_wss(self):
        if self.thread_wss:
            self.thread_wss.close_connection()  # 这里要先关闭ws连接，再关闭线程，不然容易崩溃

            self.thread_wss.quit()
            self.thread_wss.wait()
            self.update_myinfo_signal.emit("关闭弹幕线程")

    def start_wss_info_thread(self):  ##websocks消息相关
        try:
            self.thread_wss_info = wss_info(self.mediator, self.mediator_1)
            # self.thread_wss.chat_single.connect(self._chat, Qt.ConnectionType.QueuedConnection)      #聊天信号
            self.thread_wss_info.gift_list_single.connect(self._gift_list)
            self.thread_wss_info.user_list_single.connect(
                self._user_list, Qt.ConnectionType.QueuedConnection
            )
            self.thread_wss_info.reply_message_single.connect(
                self.send_msg, Qt.ConnectionType.QueuedConnection
            )
            self.thread_wss_info.play_gift_effect.connect(
                self.gift_url_list, Qt.ConnectionType.QueuedConnection
            )
            # self.thread_wss_info.pk_user_single.connect(self._pk_list)
            self.thread_wss_info.pk_score_single.connect(self._pk_score)
            self.update_myinfo_signal.emit("wss辅助线程 开启")
            self.thread_wss_info.start()
        except Exception as e:
            print(f"线程启动失败: {e}")

    def close_wss_info_thread(self):
        try:
            if self.thread_wss_info:
                self.thread_wss_info.stop_thread = (
                    True  # 这里要先关闭ws连接，再关闭线程，不然容易崩溃
                )
                self.thread_wss_info.quit()
                self.thread_wss_info.wait()
                self.update_myinfo_signal.emit("wss辅助线程 关闭")
                # print("关闭消息处理线程")
        except Exception as e:
            print(f"线程关闭失败: {e}")

    def start_auto_reply_message_thread(self, checked):  ##自动回复相关
        # print(f"准备启动线程")
        # print(self.user_cookies)
        # print(self.liveRoomId)

        try:
            if self.user_cookies is not None and checked == True:
                self.thread_auto_reply_message = auto_reply_message(
                    self.mediator_1, self.liveRoomId, self.user_cookies
                )
                self.thread_auto_reply_message.reply_info_single.connect(
                    self._reply_info, Qt.ConnectionType.QueuedConnection
                )
                self.thread_auto_reply_message.start()
                self.update_myinfo_signal.emit("自动回复线程 开启")
                # print(f"启动自动回复线程")
            elif checked == False:
                if self.thread_auto_reply_message:
                    self.thread_auto_reply_message.stop_thread = True
                    self.thread_auto_reply_message.quit()
                    self.thread_auto_reply_message.wait()
                    self.update_myinfo_signal.emit("自动回复线程 关闭")
                    # print(f"关闭自动回复线程成功")
        except Exception as e:
            print(f"线程启动失败: {e}")

    def start_auto_link(self):  ##点赞相关
        try:
            if (
                self.user_cookies is not None
                and self.liveRoomId != ""
                and self.thread_auto_like is  None
            ):
                like_num = self.ui.spinBox.value()
                self.thread_auto_like = auto_like(
                    self.liveRoomId, self.user_cookies, like_num
                )
                self.thread_auto_like.auto_like_message.connect(
                    self.update_myinfo, Qt.ConnectionType.QueuedConnection
                )
                self.thread_auto_like.close_auto_like_single.connect(
                    self.close_start_auto_link, Qt.ConnectionType.QueuedConnection
                )
                self.thread_auto_like.start()
                self.update_myinfo_signal.emit("自动点赞 开启")
                # print(f"启动自动回复线程")
        except Exception as e:
            print(f"线程启动失败: {e}")

    def close_start_auto_link(self):

        try:
            # if self.thread_auto_like:
            self.thread_auto_like.stop_thread == True
            self.thread_auto_like.quit()
            self.thread_auto_like.wait()
            self.thread_auto_like = None
            self.update_myinfo_signal.emit("自动点赞线程 关闭")
        except Exception as e:
            print(f"线程关闭失败: {e}")

    def move_gift_effect(self, x, y):
        # 将gift_effect移动到self.widget的位置（相对于屏幕）
        self.gift_effect.move(x, y)

    def eventFilter(self, watched, event):
        if watched == self and (
            event.type() == QEvent.Move or event.type() == QEvent.Resize
        ):
            # 当主窗口移动或调整大小时，重新计算并更新widget的位置
            self.update_widget_position()
        return super().eventFilter(watched, event)

    def update_widget_position(self):
        # 获取self.widget相对于屏幕的位置
        global_pos = self.widget.mapToGlobal(self.widget.pos())
        x = global_pos.x()
        y = global_pos.y()
        self.position_tracker.position_changed.emit(x, y)

    def gift_url_list(self, url):  ## 特效播放列表
        self.url_queue.put(url)
        print(f"新添加:{url}")
        if self.url_queue.qsize() == 1 and self.gift_effect_playing == False:
            self.play_gift_effect()

    def play_gift_effect(self):  ##礼物特效alpha播放器
        # self.gift_effect.page().loadFinished.connect(self.on_page_loaded)
        # global_pos = self.widget.mapToGlobal(self.widget.pos())  #获取直播视频播放窗口位置
        # x = global_pos.x()
        # y = global_pos.y()
        
        #self.gift_effect.show()
        
        
        # self.gift_effect.move(x+1, y+2)  #移动本窗口到视频播放窗口
        # self.gift_effect.move(x, y)

        # gift_url = "https://1aaaumqg5w1ggjgyjkhig3tnw5mxcdirmbl5qkpalw4.vegslb.com:8889/lf5-webcastcdn-tos.douyinstatic.com/obj/webcast/e6da55c3970143b1df64d92e11a99cdb.zip?jump_ttl=1&bdcdn_rkey=vt80_czcm02"

        gift_url = self.url_queue.get()
        gift_url = gift_url.replace(
            "sf1-hscdn-tos.pstatp.com", "sf1-cdn-tos.huoshanstatic.com"
        )
        print(f"即将播放:{gift_url}")

        video_html = f"""
<html>
<head>
    <script src="js/qwebchannel.js"></script>
</head>
<body style="background-color: transparent; margin: 0; padding: 0;">
    <video id="video" style="display:none;" width="100%" height="100%" controls autoplay muted></video>
    <!-- 渲染容器 -->
    <div id="container" data-zip-url={gift_url}></div>
    <!-- 播放按钮 -->
    <button id="play-button" style="display:none;">Play</button>
    <script src="js/jszip.min.js"></script>
    <script src="js/three.min.js"></script>
    <script src="js/alpha.js"></script>
</body>
</html>
"""

        # 创建一个包含视频的本地 HTML 文件
        if not os.path.exists('src'):
            os.makedirs('src')
        with open("src/video.html", "w") as f:
            f.write(video_html)

        # 加载本地 HTML 文件
        self.gift_effect.load(QUrl.fromLocalFile(os.path.abspath("src/video.html")))
        self.gift_effect_playing = True
        self.gift_effect.show()

    @pyqtSlot()
    def pyqt_slot_video_ended(self):  ##特效播放完成后关闭(释放资源)
        if not self.url_queue.empty():
            self.play_gift_effect()
        # print("视频播放完成啦！")
        else:
            self.gift_effect.close()
            #del self.gift_effect
            self.gift_effect_playing = False

    def parseLiveRoomUrl(self, url):  ##获取直播间信息
        headers = {
            "authority": "live.douyin.com",
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "cache-control": "max-age=0",
            "cookie": "xgplayer_user_id=251959789708; passport_assist_user=Cj1YUtyK7x-Br11SPK-ckKl61u5KX_SherEuuGPYIkLjtmV3X8m3EU1BAGVoO541Sp_jwUa8lBlNmbaOQqheGkoKPOVVH42rXu6KEb9WR85pUw4_qNHfbcotEO-cml5itrJowMBlYXDaB-GDqJwNMxMElMoZUycGhzdNVAT4XxCJ_74NGImv1lQgASIBA3Iymus%3D; n_mh=nNwOatDm453msvu0tqEj4bZm3NsIprwo6zSkIjLfICk; LOGIN_STATUS=1; store-region=cn-sh; store-region-src=uid; sid_guard=b177a545374483168432b16b963f04d5%7C1697713285%7C5183999%7CMon%2C+18-Dec-2023+11%3A01%3A24+GMT; ttwid=1%7C9SEGPfK9oK2Ku60vf6jyt7h6JWbBu4N_-kwQdU-SPd8%7C1697721607%7Cc406088cffa073546db29932058720720521571b92ba67ba902a70e5aaffd5d6; odin_tt=1f738575cbcd5084c21c7172736e90f845037328a006beefec4260bf8257290e2d31b437856575c6caeccf88af429213; __live_version__=%221.1.1.6725%22; device_web_cpu_core=16; device_web_memory_size=8; live_use_vvc=%22false%22; csrf_session_id=38b68b1e672a92baa9dcb4d6fd1c5325; FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%7D; __ac_nonce=0658d6780004b23f5d0a8; __ac_signature=_02B4Z6wo00f01Klw1CQAAIDAXxndAbr7OHypUNCAAE.WSwYKFjGSE9AfNTumbVmy1cCS8zqYTadqTl8vHoAv7RMb8THl082YemGIElJtZYhmiH-NnOx53mVMRC7MM8xuavIXc-9rE7ZEgXaA13; webcast_leading_last_show_time=1703765888956; webcast_leading_total_show_times=1; webcast_local_quality=sd; xg_device_score=7.90435294117647; live_can_add_dy_2_desktop=%221%22; msToken=sTwrsWOpxsxXsirEl0V0d0hkbGLze4faRtqNZrIZIuY8GYgo2J9a0RcrN7r_l179C9AQHmmloI94oDvV8_owiAg6zHueq7lX6TgbKBN6OZnyfvZ6OJyo2SQYawIB_g==; tt_scid=NyxJTt.vWxv79efmWAzT2ZAiLSuybiEOWF0wiVYs5KngMuBf8oz5sqzpg5XoSPmie930; pwa2=%220%7C0%7C1%7C0%22; download_guide=%223%2F20231228%2F0%22; msToken=of81bsT85wrbQ9nVOK3WZqQwwku95KW-wLfjFZOef2Orr8PRQVte27t6Mkc_9c_ROePolK97lKVG3IL5xrW6GY6mdUDB0EcBPfnm8-OAShXzlELOxBBCdiQYIjCGpQ==; IsDouyinActive=false; odin_tt=7409a7607c84ba28f27c62495a206c66926666f2bbf038c847b27817acbdbff28c3cf5930de4681d3cfd4c1139dd557e; ttwid=1%7C9SEGPfK9oK2Ku60vf6jyt7h6JWbBu4N_-kwQdU-SPd8%7C1697721607%7Cc406088cffa073546db29932058720720521571b92ba67ba902a70e5aaffd5d6",
            "referer": "https://live.douyin.com/721566130345?cover_type=&enter_from_merge=web_live&enter_method=web_card&game_name=&is_recommend=&live_type=game&more_detail=&room_id=7317569386624125734&stream_type=vertical&title_type=&web_live_tab=all",
            "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
        }
        try:
            res = requests.get(url=url, headers=headers)
            # print(res)
        except requests.RequestException as e:
            logging.error(f"请求直播页面失败: {e}")
            return None
        data = res.cookies.get_dict()
        ttwid = data["ttwid"]
        self.ttwid = data["ttwid"]
        res_text = res.text

        res_user_unique_id = re.search(
            r'user_unique_id\\":\\"(\d+)', res_text
        )  # "user_unique_id\":\"7424905546933077542\"
        if res_user_unique_id:
            user_unique_id = res_user_unique_id.group(1)
            self.user_unique_id = user_unique_id
        # logging.debug(f"user_unique_id: {user_unique_id}")
        else:
            logging.error("未找到用户唯一ID的匹配信息")
            return None

        res_web_rid = re.search(
            r'"web_rid\\":\\"([^"]*)\\"', res_text
        )  # \"web_rid\":\"353070745046\", 实际就是抖音ID
        # print(res_web_rid)
        if res_web_rid:
            web_rid = res_web_rid.group(1)
            # print(web_rid)
            self.web_rid = web_rid

        # logging.debug(f"user_unique_id: {user_unique_id}")
        else:
            logging.error("未找到web_rid")
            return None

        res_room_info = re.search(
            r'room\\":{.*\\"id_str\\":\\"(\d+)\\".*,\\"status\\":(\d+).*"title\\":\\"([^"]*)\\"',
            res_text,
        )
        if res_room_info:
            room_id_str = res_room_info.group(1)
            room_status = res_room_info.group(2)
            room_title = res_room_info.group(3)
            logging.debug(f"房间标题: {room_title}")
            if room_status == "4":
                logging.error("直播已结束")
                self.update_myinfo_signal.emit("直播已结束！！！")
                return None
        else:
            logging.error("未找到房间信息的匹配内容")
            self.update_myinfo_signal.emit("未找到房间信息的匹配内容")
            return None

        res_room = re.search(r'roomId\\":\\"(\d+)\\"', res_text)
        if res_room:
            liveRoomId = res_room.group(1)
            self.liveRoomId = liveRoomId
            self.update_myinfo_signal.emit(f"获取房间号成功: {self.liveRoomId}")
        else:
            logging.error("未找到直播间ID的匹配内容")
            return None

        # 获取直播主播的uid和昵称等信息
        live_room_search = re.search(r'owner\\":(.*?),\\"room_auth', res_text)
        if live_room_search:
            live_room_res = live_room_search.group(1).replace('\\"', '"')
            try:
                live_room_info = json.loads(live_room_res)
                author_name = live_room_info["nickname"]
            except json.JSONDecodeError as e:
                logging.error(f"解析主播信息失败: {e}")
                return None
        else:
            logging.error("未找到主播信息的匹配内容")
            return None

        # 获取m3u8直播流地址
        res_stream = re.search(r'hls_pull_url_map\\":(\{.*?})', res_text)
        # print(res_stream)
        if res_stream:
            res_stream_m3u8s = json.loads(res_stream.group(1).replace('\\"', '"'))
            res_m3u8_hd1 = res_stream_m3u8s.get("FULL_HD1", "").replace("http", "https")
            if not res_m3u8_hd1:
                res_m3u8_hd1 = res_stream_m3u8s.get("HD1", "").replace("http", "https")
                self.update_myinfo_signal.emit(f"获取推流地址成功: {res_m3u8_hd1}")
            logging.debug(f"直播流m3u8链接地址是: {res_m3u8_hd1}")
        else:
            logging.error("未找到M3U8直播流地址的匹配内容")
            return None

        # 找到flv直播流地址
        # res_flv_search = re.search(r'flv_pull_url\\":\\"(.*?)\\"', res_text)
        res_flv_search = re.search(r'flv_pull_url\\":(\{.*?})', res_text)
        if res_flv_search:
            res_stream_flvs = json.loads(
                res_flv_search.group(1)
                .replace('\\"', '"')
                .replace("\\u0026", "&")
                .replace("only_audio=1", "only_audio=0")
            )
            res_flv_hd1 = res_stream_flvs.get("FULL_HD1", "").replace("http", "https")
            if not res_flv_hd1:
                res_flv_hd1 = res_stream_flvs.get("HD1", "").replace("http", "https")
                if not res_flv_hd1:
                    res_flv_hd1 = res_stream_flvs.get("SD1", "").replace(
                        "http", "https"
                    )

        else:
            logging.error("未找到FLV直播流地址的匹配内容")
            return None

        return RoomInfo(
            room_id=liveRoomId, m3u8_adr=res_flv_hd1, author_name=author_name
        )

    def show_dialog1(self):
        self.dialog1 = dialog1(self.mediator)
        self.dialog1.exec_()

    def show_dialog2(self):
        self.dialog2 = dialog2(self.mediator)
        self.dialog2.exec_()

    def show_dialog3(self):
        self.dialog3 = dialog3(self.mediator)
        self.dialog3.exec_()

    def show_dialog4(self):
        self.dialog4 = dialog4(self.liveRoomId, self.user_cookies)
        self.dialog4.show()

    def show_dialog5(self):
        self.dialog5 = dialog5(self.mediator)
        self.dialog5.show()


# ------------------------------------------------------------------------
#  线程

"""
qrcode 

调用二维码 线程

"""


class QR_code(QThread):
    cookies_signal = pyqtSignal(dict)
    qrcode_image_signal = pyqtSignal(QPixmap)
    close_QR_code_QThread_signal = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.stop_thread = False
        session = ""

        ##获取qrcode相关
        self.session = session
        self.login_url = "https://sso.douyin.com/get_qrcode/"
        self.check_login_url = "https://sso.douyin.com/check_qrconnect/"
        self.max_retries = 3  # 最大重试次数
        self.retry_delay = 2  # 初始重试延迟时间（秒）
        self.max_waiting_times = 10

    def run(self):
        self.login_invoke()

    def get_qrcode(self):
        retries = 0
        delay = self.retry_delay
        while retries < self.max_retries:
            response = self.session.get(self.login_url)
            # print(response)
            if response.status_code == 200:
                qr_data = response.json()
                print("Received QR data:", qr_data)  # 添加调试信息
                qr_text = qr_data.get("data", {}).get("qrcode_index_url", "")
                print("QR Code URL:", qr_text)  # 打印二维码链接
                img = qrcode.make(qr_text)
                self.display_qr_code(img)  # 显示二维码
                token = qr_data.get("data", {}).get("token")
                if not token:
                    raise KeyError("Token not found in QR data.")
                return token
            else:
                print(
                    f"Failed to get QR code. Status code: {response.status_code}. Retrying..."
                )
                retries += 1
                time.sleep(delay)
                delay *= 2  # 增加重试延迟时间
        raise Exception("Failed to get QR code after multiple retries.")

    # @staticmethod
    def display_qr_code(self, img):
        # 将二维码显示在窗口中
        # img.show()
        # self.qrcode_obtained.emit(img)
        img = img.resize((330, 330))
        buffer = BytesIO()
        img.save(buffer, format="PNG")
        pixmap = QPixmap()
        pixmap.loadFromData(buffer.getvalue())
        self.qrcode_image_signal.emit(pixmap)

    def check_login_status(self, token):
        retries = 0
        waiting_times = 0
        delay = self.retry_delay

        while retries < self.max_retries and waiting_times < self.max_waiting_times:
            params = {"token": token}
            response = self.session.get(self.check_login_url, params=params)
            if response.status_code == 200:
                status_data = response.json()
                print("Received login status data:", status_data)  # 添加调试信息
                status = status_data.get("data", {}).get("status", "")
                if status == "1":
                    print("Please scan the QR code and confirm login.")
                elif status == "3":
                    print("Login successful!")
                    redirect_url = status_data.get("data", {}).get("redirect_url", "")
                    if redirect_url:
                        self.handle_redirect_url(redirect_url)
                        return status_data.get("data", {})
                    else:
                        raise KeyError("Redirect URL not found in login status data.")

                elif status == "EXPIRE":
                    print("QR code has expired.")
                    break
                else:
                    print("Waiting for login confirmation...")
                    waiting_times += 1
            else:
                print(
                    f"Failed to check login status. Status code: {response.status_code}. Retrying..."
                )
                retries += 1
                time.sleep(delay)
                delay *= 2  # 增加重试延迟时间
            time.sleep(5)
        raise ValueError("Failed to check login status after multiple retries.")

    def handle_redirect_url(self, redirect_url):
        # 处理重定向URL，获取新的Cookie
        response = self.session.get(redirect_url, allow_redirects=True)

        # 检查所有重定向响应中的Set-Cookie头
        for resp in response.history + [response]:
            if "Set-Cookie" in resp.headers:
                set_cookie_header = resp.headers["Set-Cookie"]
                # 分割成多个Cookie字符串
                cookies = [
                    cookie.strip()
                    for cookie in set_cookie_header.split(";")
                    if "=" in cookie
                ]
                # 更新Session的Cookie
                for cookie in cookies:
                    name, value = cookie.split("=", 1)
                    self.session.cookies.set(name, value)

        if response.status_code == 200:
            print("Redirect URL processed successfully.")
            # 获取新的Cookie
            new_cookies = self.session.cookies.get_dict()
            # self.user_cookies = new_cookies
            self.cookies_signal.emit(new_cookies)

            print("New Cookies:", new_cookies)
            return new_cookies
        else:
            print(
                f"Failed to process redirect URL. Status code: {response.status_code}"
            )
            return {}

    def login(self):
        token = self.get_qrcode()
        session_data = self.check_login_status(token)
        # self.new_query_login_info.emit()
        return session_data

    def login_invoke(self):
        headers = {
            "Accept": "application/json, text/javascript",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Content-Type": "application/x-www-form-urlencoded",
            "Cookie": (
                "bd_ticket_guard_client_web_domain=2; store-region=cn-zj; store-region-src=uid;"
                " UIFID_TEMP=973a3fd64dcc46a3490fd9b60d4a8e663b34df4ccc4bbcf97643172fb712d8b04387241f5764b8b6679b904f40b9d01f1f17635203323be5b6ed7953b13983c81da4ff067e2e9e686c0021c26c1c3ab7;"
                " passport_csrf_token=9b1665aae2760a833d4205996935e2a6;"
                " passport_csrf_token_default=9b1665aae2760a833d4205996935e2a6;"
                " hevc_supported=true;"
                " ttwid=1%7CqArlkEadJJBQWS46o7g6PvFGTFCYglEOdf3G23fTZD0%7C1728483542%7Cc97a4351a674099ec30e9923730671f28ba900b908bdd3dbc297bef29bcf1987;"
                " FORCE_LOGIN=%7B%22videoConsumedRemainSeconds%22%3A180%2C%22isForcePopClose%22%3A1%7D;"
                " is_staff_user=false;"
                " SelfTabRedDotControl=%5B%5D;"
                " _bd_ticket_crypt_doamin=2;"
                " __security_server_data_status=1;"
                " publish_badge_show_info=%220%2C0%2C0%2C1728486121176%22;"
                " live_use_vvc=%22false%22;"
                " volume_info=%7B%22isUserMute%22%3Afalse%2C%22isMute%22%3Afalse%2C%22volume%22%3A0.175%7D;"
                " download_guide=%223%2F20241012%2F0%22;"
                " pwa2=%220%7C0%7C3%7C0%22;"
                " stream_player_status_params=%22%7B%5C%22is_auto_play%5C%22%3A0%2C%5C%22is_full_screen%5C%22%3A0%2C%5C%22is_full_webscreen%5C%22%3A0%2C%5C%22is_mute%5C%22%3A0%2C%5C%22is_speed%5C%22%3A1%2C%5C%22is_visible%5C%22%3A0%7D%22;"
                " strategyABtestKey=%221728819267.059%22;"
                " webcast_leading_last_show_time=1728819284117;"
                " webcast_leading_total_show_times=1;"
                " __live_version__=%221.1.2.4139%22;"
                " live_can_add_dy_2_desktop=%220%22;"
                " h265ErrorNum=-1;"
                " webcast_local_quality=origin;"
                " FOLLOW_NUMBER_YELLOW_POINT_INFO=%22MS4wLjABAAAAn5Ja2AH0rwxrvQTx0N5sZsxPOO2IvGcFtGuyJs2ur6JHUwyWcdyVF_choLGqOmMG%2F1728835200000%2F0%2F1728823319711%2F0%22;"
                " FOLLOW_LIVE_POINT_INFO=%22MS4wLjABAAAAn5Ja2AH0rwxrvQTx0N5sZsxPOO2IvGcFtGuyJs2ur6JHUwyWcdyVF_choLGqOmMG%2F1728835200000%2F1728819271256%2F1728823970208%2F0%22;"
                " my_rd=2;"
                " d_ticket=ff7817f6e288dc436c1eb0e0dd95ec1575e83;"
                " n_mh=YQsr1blwqqsU2Yhk1rnwCk0C1Dl3rqUy7YDxEM3BJEE;"
                " toutiao_sso_user=3bce610fae9863474344539302a56e70;"
                " toutiao_sso_user_ss=3bce610fae9863474344539302a56e70;"
                " passport_auth_status=d5a2cad551aff9453c1a7a477f0dd9d0%2Cb94aea676860d4d46f26dc53be54f99c;"
                " passport_auth_status_ss=d5a2cad551aff9453c1a7a477f0dd9d0%2Cb94aea676860d4d46f26dc53be54f99c;"
                " _bd_ticket_crypt_cookie=4299c9b866b9b0760d066a4074c94e28;"
                " sso_uid_tt=30d1a7aed5813a7e6bb9d78422516cd9;"
                " sso_uid_tt_ss=30d1a7aed5813a7e6bb9d78422516cd9;"
                " sid_ucp_sso_v1=1.0.0-KDlhMTNiNmU5N2NkZGY5OTc5YWZlOTM1MzYzNzExN2JiYTBmZDUyZGYKCRDdh6-4BhjvMRoCbHEiIDNiY2U2MTBmYWU5ODYzNDc0MzQ0NTM5MzAyYTU2ZTcw;"
                " ssid_ucp_sso_v1=1.0.0-KDlhMTNiNmU5N2NkZGY5OTc5YWZlOTM1MzYzNzExN2JiYTBmZDUyZGYKCRDdh6-4BhjvMRoCbHEiIDNiY2U2MTBmYWU5ODYzNDc0MzQ0NTM5MzAyYTU2ZTcw;"
                " sid_guard=c72a4da9cda2c7252dc9b8e5f4f48129%7C1728824285%7C21600%7CSun%2C+13-Oct-2024+18%3A58%3A05+GMT;"
                " uid_tt=c61ad93416645a956a4a719452610cac;"
                " uid_tt_ss=c61ad93416645a956a4a719452610cac;"
                " sid_tt=c72a4da9cda2c7252dc9b8e5f4f48129;"
                " sessionid=c72a4da9cda2c7252dc9b8e5f4f48129;"
                " sessionid_ss=c72a4da9cda2c7252dc9b8e5f4f48129;"
                " sid_ucp_v1=1.0.0-KGQwOTYyZDE2OTE2Y2FmOTUxYTdhMjFmZjA4MjAxOGQwMzgwNTFkNzkKCBDdh6-4BhgNGgJscSI gYzcyYTRkYTljZGEyYzcyNTJkYzliOGU1ZjRmNDgxMjk;"
                " ssid_ucp_v1=1.0.0-KGQwOTYyZDE2OTE2Y2FmOTUxYTdhMjFmZjA4MjAxOGQwMzgwNTFkNzkKCBDdh6-4BhgNGgJscSI gYzcyYTRkYTljZGEyYzcyNTJkYzliOGU1ZjRmNDgxMjk;"
                " stream_recommend_feed_params=%22%7B%5C%22cookie_enabled%5C%22%3Atrue%2C%5C%22screen_width%5C%22%3A2560%2C%5C%22screen_height%5C%22%3A1440%2C%5C%22browser_online%5C%22%3Atrue%2C%5C%22cpu_core_num%5C%22%3A8%2C%5C%22device_memory%5C%22%3A8%2C%5C%22downlink%5C%22%3A5.15%2C%5C%22effective_type%5C%22%3A%5C%224g%5C%22%2C%5C%22round_trip_time%5C%22%3A50%7D%22;"
                " home_can_add_dy_2_desktop=%221%22;"
                " bd_ticket_guard_client_data=eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCRWdHNFAzMTZ6MzJQaEczdlpJNG9sMUxrd0JaTlVZakZpUHFOdFFMTzNFR0JOaXcxZnZFaXMzdzAyU1FQSWlFRTdnUQQwIiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoyfQ%3D%3D;"
                " odin_tt=b2d89ee52c691f3988e138d4d3e83d3e3cfd25ddca3a8a7f469d9b5886744068e978b2a5529b3faabaac7108c0ebbfd6e2f78f2655af059f7d544483ee7a693a4c5b0cdd184abaf353aa7797985e9eb5;"
                " IsDouyinActive=true;"
                " WallpaperGuide=%7B%22showTime%22%3A1728824294955%2C%22closeTime%22%3A0%2C%22showCount%22%3A1%2C%22cursor1%22%3A16%2C%22cursor2%22%3A4%7D;"
                " biz_trace_id=64ff0cb4"
            ),
            "Origin": "https://www.douyin.com",
            "Priority": "u=1, i",
            "Referer": "https://www.douyin.com/",
            "Sec-Ch-Ua": '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
            "Sec-Ch-Ua-Mobile": "?0",
            "Sec-Ch-Ua-Platform": '"Windows"',
            "Sec-Fetch-Dest": "empty",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Site": "same-site",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
            "X-Tt-Passport-Csrf-Token": "9b1665aae2760a833d4205996935e2a6",
            "X-Tt-Passport-Trace-Id": "64ff0cb4",
        }

        session = requests.Session()
        session.headers.update(headers)
        self.session = session
        # douyin_login = DouyinLogin(session)
        try:
            session_data = self.login()
            print("Session data:", session_data)
            self.close_QR_code_QThread_signal.emit()  # 关闭线程
        except Exception as e:
            print("An error occurred:", e)
            self.close_QR_code_QThread_signal.emit()


""" 播放器线程 """


class start_wss(QThread):
    chat_single = pyqtSignal(str)  # 聊天信号
    gift_single = pyqtSignal(str)  # 礼物信号
    like_single = pyqtSignal(str)  # 点赞信号
    social_single = pyqtSignal(str)  # 关注信号
    enter_single = pyqtSignal(str)  # 进入信号
    roominfo_single = pyqtSignal(str, str)  # 房间信息信号
    # total_info_single = pyqtSignal(dict) #传输字典
    send_data = pyqtSignal(dict)

    # chat_single = pyqtSignal(str)
    # chat_single = pyqtSignal(str)
    emoji_mapping = {
        "[过年牛]": "src/pic/emoji/[过年牛].png",
        "[元宝]": "src/pic/emoji/[元宝].png",
        "[鞭炮]": "src/pic/emoji/[鞭炮].png",
        "[汤圆]": "src/pic/emoji/[汤圆].png",
        "[戴口罩]": "src/pic/emoji/[戴口罩].png",
        "[勤洗手]": "src/pic/emoji/[勤洗手].png",
        "[不信谣言]": "src/pic/emoji/[不信谣言].png",
        "[情书]": "src/pic/emoji/[情书].png",
        "[微笑]": "src/pic/emoji/[微笑].png",
        "[色]": "src/pic/emoji/[色].png",
        "[爱慕]": "src/pic/emoji/[爱慕].png",
        "[发呆]": "src/pic/emoji/[发呆].png",
        "[惊呆]": "src/pic/emoji/[惊呆].png",
        "[酷拽]": "src/pic/emoji/[酷拽].png",
        "[抠鼻]": "src/pic/emoji/[抠鼻].png",
        "[流泪]": "src/pic/emoji/[流泪].png",
        "[捂脸]": "src/pic/emoji/[捂脸].png",
        "[发怒]": "src/pic/emoji/[发怒].png",
        "[呲牙]": "src/pic/emoji/[呲牙].png",
        "[一起加油]": "src/pic/emoji/[一起加油].png",
        "[睡]": "src/pic/emoji/[睡].png",
        "[鼾睡]": "src/pic/emoji/[鼾睡].png",
        "[害羞]": "src/pic/emoji/[害羞].png",
        "[调皮]": "src/pic/emoji/[调皮].png",
        "[可爱]": "src/pic/emoji/[可爱].png",
        "[晕]": "src/pic/emoji/[晕].png",
        "[衰]": "src/pic/emoji/[衰].png",
        "[闭嘴]": "src/pic/emoji/[闭嘴].png",
        "[机智]": "src/pic/emoji/[机智].png",
        "[赞]": "src/pic/emoji/[赞].png",
        "[鼓掌]": "src/pic/emoji/[鼓掌].png",
        "[感谢]": "src/pic/emoji/[感谢].png",
        "[祈祷]": "src/pic/emoji/[祈祷].png",
        "[来看我]": "src/pic/emoji/[来看我].png",
        "[灵机一动]": "src/pic/emoji/[灵机一动].png",
        "[灵光一闪]": "src/pic/emoji/[灵光一闪].png",
        "[耶]": "src/pic/emoji/[耶].png",
        "[打脸]": "src/pic/emoji/[打脸].png",
        "[大笑]": "src/pic/emoji/[大笑].png",
        "[哈欠]": "src/pic/emoji/[哈欠].png",
        "[震惊]": "src/pic/emoji/[震惊].png",
        "[送心]": "src/pic/emoji/[送心].png",
        "[困]": "src/pic/emoji/[困].png",
        "[疑问]": "src/pic/emoji/[疑问].png",
        "[what]": "src/pic/emoji/[what].png",
        "[泣不成声]": "src/pic/emoji/[泣不成声].png",
        "[小鼓掌]": "src/pic/emoji/[小鼓掌].png",
        "[大金牙]": "src/pic/emoji/[大金牙].png",
        "[偷笑]": "src/pic/emoji/[偷笑].png",
        "[石化]": "src/pic/emoji/[石化].png",
        "[思考]": "src/pic/emoji/[思考].png",
        "[吐血]": "src/pic/emoji/[吐血].png",
        "[可怜]": "src/pic/emoji/[可怜].png",
        "[嘘]": "src/pic/emoji/[嘘].png",
        "[撇嘴]": "src/pic/emoji/[撇嘴].png",
        "[尴尬]": "src/pic/emoji/[尴尬].png",
        "[黑线]": "src/pic/emoji/[黑线].png",
        "[笑哭]": "src/pic/emoji/[笑哭].png",
        "[生病]": "src/pic/emoji/[生病].png",
        "[雾霾]": "src/pic/emoji/[雾霾].png",
        "[奸笑]": "src/pic/emoji/[奸笑].png",
        "[得意]": "src/pic/emoji/[得意].png",
        "[憨笑]": "src/pic/emoji/[憨笑].png",
        "[坏笑]": "src/pic/emoji/[坏笑].png",
        "[抓狂]": "src/pic/emoji/[抓狂].png",
        "[泪奔]": "src/pic/emoji/[泪奔].png",
        "[钱]": "src/pic/emoji/[钱].png",
        "[亲亲]": "src/pic/emoji/[亲亲].png",
        "[吻]": "src/pic/emoji/[吻].png",
        "[恐惧]": "src/pic/emoji/[恐惧].png",
        "[愉快]": "src/pic/emoji/[愉快].png",
        "[笑]": "src/pic/emoji/[笑].png",
        "[快哭了]": "src/pic/emoji/[快哭了].png",
        "[翻白眼]": "src/pic/emoji/[翻白眼].png",
        "[傲慢]": "src/pic/emoji/[傲慢].png",
        "[互粉]": "src/pic/emoji/[互粉].png",
        "[我想静静]": "src/pic/emoji/[我想静静].png",
        "[委屈]": "src/pic/emoji/[委屈].png",
        "[舔屏]": "src/pic/emoji/[舔屏].png",
        "[鄙视]": "src/pic/emoji/[鄙视].png",
        "[飞吻]": "src/pic/emoji/[飞吻].png",
        "[再见]": "src/pic/emoji/[再见].png",
        "[紫薇别走]": "src/pic/emoji/[紫薇别走].png",
        "[听歌]": "src/pic/emoji/[听歌].png",
        "[拥抱]": "src/pic/emoji/[拥抱].png",
        "[求抱抱]": "src/pic/emoji/[求抱抱].png",
        "[绝望的凝视]": "src/pic/emoji/[绝望的凝视].png",
        "[不失礼貌的微笑]": "src/pic/emoji/[不失礼貌的微笑].png",
        "[吐舌]": "src/pic/emoji/[吐舌].png",
        "[呆无辜]": "src/pic/emoji/[呆无辜].png",
        "[看]": "src/pic/emoji/[看].png",
        "[白眼]": "src/pic/emoji/[白眼].png",
        "[熊吉]": "src/pic/emoji/[熊吉].png",
        "[猪头]": "src/pic/emoji/[猪头].png",
        "[不看]": "src/pic/emoji/[不看].png",
        "[冷漠]": "src/pic/emoji/[冷漠].png",
        "[微笑袋鼠]": "src/pic/emoji/[微笑袋鼠].png",
        "[凝视]": "src/pic/emoji/[凝视].png",
        "[暗中观察]": "src/pic/emoji/[暗中观察].png",
        "[骷髅]": "src/pic/emoji/[骷髅].png",
        "[黑脸]": "src/pic/emoji/[黑脸].png",
        "[吃瓜群众]": "src/pic/emoji/[吃瓜群众].png",
        "[绿帽子]": "src/pic/emoji/[绿帽子].png",
        "[流汗]": "src/pic/emoji/[流汗].png",
        "[汗]": "src/pic/emoji/[汗].png",
        "[摸头]": "src/pic/emoji/[摸头].png",
        "[皱眉]": "src/pic/emoji/[皱眉].png",
        "[擦汗]": "src/pic/emoji/[擦汗].png",
        "[红脸]": "src/pic/emoji/[红脸].png",
        "[尬笑]": "src/pic/emoji/[尬笑].png",
        "[做鬼脸]": "src/pic/emoji/[做鬼脸].png",
        "[强]": "src/pic/emoji/[强].png",
        "[如花]": "src/pic/emoji/[如花].png",
        "[吐]": "src/pic/emoji/[吐].png",
        "[惊喜]": "src/pic/emoji/[惊喜].png",
        "[敲打]": "src/pic/emoji/[敲打].png",
        "[奋斗]": "src/pic/emoji/[奋斗].png",
        "[吐彩虹]": "src/pic/emoji/[吐彩虹].png",
        "[大哭]": "src/pic/emoji/[大哭].png",
        "[嘿哈]": "src/pic/emoji/[嘿哈].png",
        "[加好友]": "src/pic/emoji/[加好友].png",
        "[惊恐]": "src/pic/emoji/[惊恐].png",
        "[惊讶]": "src/pic/emoji/[惊讶].png",
        "[囧]": "src/pic/emoji/[囧].png",
        "[难过]": "src/pic/emoji/[难过].png",
        "[斜眼]": "src/pic/emoji/[斜眼].png",
        "[阴险]": "src/pic/emoji/[阴险].png",
        "[左哼哼]": "src/pic/emoji/[左哼哼].png",
        "[右哼哼]": "src/pic/emoji/[右哼哼].png",
        "[悠闲]": "src/pic/emoji/[悠闲].png",
        "[咒骂]": "src/pic/emoji/[咒骂].png",
        "[比心]": "src/pic/emoji/[比心].png",
        "[强壮]": "src/pic/emoji/[强壮].png",
        "[加油]": "src/pic/emoji/[加油].png",
        "[碰拳]": "src/pic/emoji/[碰拳].png",
        "[OK]": "src/pic/emoji/[OK].png",
        "[ok]": "src/pic/emoji/[ok].png",
        "[击掌]": "src/pic/emoji/[击掌].png",
        "[左上]": "src/pic/emoji/[左上].png",
        "[握手]": "src/pic/emoji/[握手].png",
        "[抱拳]": "src/pic/emoji/[抱拳].png",
        "[勾引]": "src/pic/emoji/[勾引].png",
        "[拳头]": "src/pic/emoji/[拳头].png",
        "[弱]": "src/pic/emoji/[弱].png",
        "[胜利]": "src/pic/emoji/[胜利].png",
        "[右边]": "src/pic/emoji/[右边].png",
        "[左边]": "src/pic/emoji/[左边].png",
        "[嘴唇]": "src/pic/emoji/[嘴唇].png",
        "[kiss]": "src/pic/emoji/[kiss].png",
        "[去污粉]": "src/pic/emoji/[去污粉].png",
        "[666]": "src/pic/emoji/[666].png",
        "[玫瑰]": "src/pic/emoji/[玫瑰].png",
        "[胡瓜]": "src/pic/emoji/[胡瓜].png",
        "[啤酒]": "src/pic/emoji/[啤酒].png",
        "[18禁]": "src/pic/emoji/[18禁].png",
        "[我太难了]": "src/pic/emoji/[我太难了].png",
        "[菜刀]": "src/pic/emoji/[菜刀].png",
        "[刀]": "src/pic/emoji/[刀].png",
        "[V5]": "src/pic/emoji/[V5].png",
        "[给力]": "src/pic/emoji/[给力].png",
        "[爱心]": "src/pic/emoji/[爱心].png",
        "[心]": "src/pic/emoji/[心].png",
        "[心碎]": "src/pic/emoji/[心碎].png",
        "[伤心]": "src/pic/emoji/[伤心].png",
        "[便便]": "src/pic/emoji/[便便].png",
        "[屎]": "src/pic/emoji/[屎].png",
        "[加鸡腿]": "src/pic/emoji/[加鸡腿].png",
        "[蛋糕]": "src/pic/emoji/[蛋糕].png",
        "[气球]": "src/pic/emoji/[气球].png",
        "[炸弹]": "src/pic/emoji/[炸弹].png",
        "[发]": "src/pic/emoji/[发].png",
        "[派对]": "src/pic/emoji/[派对].png",
        "[撒花]": "src/pic/emoji/[撒花].png",
        "[礼物]": "src/pic/emoji/[礼物].png",
        "[红包]": "src/pic/emoji/[红包].png",
        "[咖啡]": "src/pic/emoji/[咖啡].png",
        "[凋谢]": "src/pic/emoji/[凋谢].png",
        "[西瓜]": "src/pic/emoji/[西瓜].png",
        "[太阳]": "src/pic/emoji/[太阳].png",
        "[月亮]": "src/pic/emoji/[月亮].png",
        "[锦鲤]": "src/pic/emoji/[锦鲤].png",
        "[过年鼠]": "src/pic/emoji/[过年鼠].png",
        "[圣诞树]": "src/pic/emoji/[圣诞树].png",
        "[圣诞帽]": "src/pic/emoji/[圣诞帽].png",
        "[雪花]": "src/pic/emoji/[雪花].png",
        "[平安果]": "src/pic/emoji/[平安果].png",
        "[握爪]": "src/pic/emoji/[握爪].png",
        "[我酸了]": "src/pic/emoji/[我酸了].png",
        "[小黄鸭]": "src/pic/emoji/[小黄鸭].png",
        "[棒棒糖]": "src/pic/emoji/[棒棒糖].png",
        "[纸飞机]": "src/pic/emoji/[纸飞机].png",
        "[必胜]": "src/pic/emoji/[必胜].png",
        "[粽子]": "src/pic/emoji/[粽子].png",
        "[蕉绿]": "src/pic/emoji/[蕉绿].png",
        "[绝]": "src/pic/emoji/[绝].png",
        "[给跪了]": "src/pic/emoji/[给跪了].png",
        "[扎心]": "src/pic/emoji/[扎心].png",
        "[干杯]": "src/pic/emoji/[干杯].png",
        "[烟花]": "src/pic/emoji/[烟花].png",
        "[小红花]": "src/pic/emoji/[小红花].png",
        "[饺子]": "src/pic/emoji/[饺子].png",
        "[福]": "src/pic/emoji/[福].png",
        "[灯笼]": "src/pic/emoji/[灯笼].png",
        "[巧克力]": "src/pic/emoji/[巧克力].png",
        "[戒指]": "src/pic/emoji/[戒指].png",
        "[罗三炮]": "src/pic/emoji/[罗三炮].png",
    }

    def __init__(
        self,
        liveRoomId,
        user_unique_id,
        wss_signature_vaule,
        ttwid,
        mediator,
        parent=None,
    ):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.liveRoomId = liveRoomId
        self.ttwid = ttwid
        self.user_unique_id = user_unique_id
        self.wss_signature_vaule = wss_signature_vaule

        self.ws = None  # 新增，用于存储WebSocketApp实例
        self.mediator = mediator
        self.send_data.connect(
            mediator.forward_data, Qt.ConnectionType.QueuedConnection
        )

    def run(self):
        self.start_wss()

    def start_wss(self):
        self.start_time = time.time()
        websocket.enableTrace(False)
        # if hasattr(self, 'ws') and self.ws.sock and self.ws.sock.connected:
        # try:
        # self.ws.close()
        # except Exception as e:
        # logging.error(f"关闭WebSocket连接时出错: {e}")

        # 拼接获取弹幕消息的websocket的链接
        webSocketUrl = (
            "wss://webcast5-ws-web-hl.douyin.com/webcast/im/push/v2/?app_name=douyin_web&version_code=180800&webcast_sdk_version=1.0.14-beta.0&update_version_code=1.0.14-beta.0&compress=gzip&device_platform=web&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Mozilla&browser_version=5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/130.0.0.0%20Safari/537.36&browser_online=true&tz_name=Asia/Shanghai&host=https://live.douyin.com&aid=6383&live_id=1&did_rule=3&endpoint=live_pc&support_wrds=1&user_unique_id="
            + self.user_unique_id
            + "&im_path=/webcast/im/fetch/&identity=audience&need_persist_msg_count=1000&insert_task_id=&live_reason=&room_id="
            + self.liveRoomId
            + "&heartbeatDuration=1&signature="
            + self.wss_signature_vaule
            + ""
        )
        print(webSocketUrl)

        h = {
            "cookie": "ttwid=" + self.ttwid,
            "user - agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.# 536",
        }
        # print(f"Has onError method: {hasattr(self, 'onError')}")
        print(h)

        # signature = generateSignature(webSocketUrl)
        # b = Signature()
        # signature = b.generateSignature(self.liveRoomId, self.user_unique_id)
        # print(signature)

        # webSocketUrl += f"&signature={signature}"

        ws = websocket.WebSocketApp(
            webSocketUrl,
            on_message=self.onMessage,
            on_error=self.onError,
            on_close=self.onClose,
            on_open=self.onOpen,
            header=h,
        )
        self.ws = ws
        ws.run_forever()

    def onMessage(self, ws: websocket.WebSocketApp, message: bytes):
        # 相当于每一条消息
        wssPackage = PushFrame()
        # 将二进制序列化后的数据解析到此消息中
        wssPackage.ParseFromString(message)
        logId = wssPackage.logId
        # 使用gzip压缩
        decompressed = gzip.decompress(wssPackage.payload)
        payloadPackage = Response()
        payloadPackage.ParseFromString(decompressed)
        # print(payloadPackage)

        # 发送ack包
        if payloadPackage.needAck:
            self.sendAck(ws, logId, payloadPackage.internalExt)
        for msg in payloadPackage.messagesList:
            # 反对分数消息
            if msg.method == "WebcastMatchAgainstScoreMessage":
                self.unPackMatchAgainstScoreMessage(msg.payload)
                continue

            # 点赞数
            if msg.method == "WebcastLikeMessage":
                self.unPackWebcastLikeMessage(msg.payload)
                continue

            # 成员进入直播间消息
            if msg.method == "WebcastMemberMessage":
                self.unPackWebcastMemberMessage(msg.payload)
                continue

            # 礼物消息
            if msg.method == "WebcastGiftMessage":
                self.unPackWebcastGiftMessage(msg.payload)
                continue

            # 聊天消息
            if msg.method == "WebcastChatMessage":
                self.unPackWebcastChatMessage(msg.payload)
                continue

            # 关注消息
            if msg.method == "WebcastSocialMessage":
                self.unPackWebcastSocialMessage(msg.payload)
                continue

            # 房间用户发送消息
            if msg.method == "WebcastRoomUserSeqMessage":
                self.unPackWebcastRoomUserSeqMessage(msg.payload)
                continue

            # 更新粉丝票
            if msg.method == "WebcastUpdateFanTicketMessage":
                self.unPackWebcastUpdateFanTicketMessage(msg.payload)
                continue

            # 公共文本消息
            if msg.method == "WebcastCommonTextMessage":
                self.unPackWebcastCommonTextMessage(msg.payload)
                continue

            # 商品改变消息
            if msg.method == "WebcastProductChangeMessage":
                self.WebcastProductChangeMessage(msg.payload)
                continue
            # 11-8 添加
            if msg.method == "WebcastLinkMessage":
                self.WebcastLinkMessage(msg.payload)
                continue

            if msg.method == "WebcastLinkMicBattleMethod":
                self.WebcastLinkMicBattleMethod(msg.payload)
                continue

            if msg.method == "WebcastLinkMicBattleFinishMethod":
                self.WebcastLinkMicBattleFinishMethod(msg.payload)
                continue

            if msg.method == "WebcastLinkmicTeamfightScoreMessage":
                self.WebcastLinkmicTeamfightScoreMessage(msg.payload)
                continue
            # 8个
            if msg.method == "WebcastLinkmicTeamfightMessage":
                self.WebcastLinkmicTeamfightMessage(msg.payload)
                continue
            if msg.method == "WebcastLinkmicOrderSingMessage":
                self.WebcastLinkmicOrderSingMessage(msg.payload)
                continue
            if msg.method == "WebcastLinkmicOrderSingScoreMessage":
                self.WebcastLinkmicOrderSingScoreMessage(msg.payload)
                continue
            if msg.method == "WebcastLinkmicProfitMessage":
                self.WebcastLinkmicProfitMessage(msg.payload)
                continue
            if msg.method == "WebcastLinkMicMethod":
                self.WebcastLinkMicMethod(msg.payload)
                continue
            if msg.method == "WebcastLinkMicArmiesMethod":
                self.WebcastLinkMicArmiesMethod(msg.payload)
                continue
            if msg.method == "WebcastGuestBattleMessage":
                self.WebcastGuestBattleMessage(msg.payload)
                continue
            if msg.method == "WebcastGuestBattleScoreMessage":
                self.WebcastGuestBattleScoreMessage(msg.payload)
                continue
            if msg.method == "WebcastLinkSettingNotifyMessage":
                self.WebcastLinkSettingNotifyMessage(msg.payload)
                continue

    def unPackWebcastCommonTextMessage(self, data):
        commonTextMessage = CommonTextMessage()
        commonTextMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            commonTextMessage, preserving_proto_field_name=True
        )
        return data

    def WebcastProductChangeMessage(self, data):
        commonTextMessage = ProductChangeMessage()
        commonTextMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            commonTextMessage, preserving_proto_field_name=True
        )

        # PK的用户信息

    def WebcastLinkMessage(self, data):
        linkMessage = LinkMessage()
        linkMessage.ParseFromString(data)
        data = json_format.MessageToDict(linkMessage, preserving_proto_field_name=True)
        # print(data)
        # try:
        # pk_user_info = {
        # "msg_info": "pk_user",
        # }
        # if "linkedlistchangecontent" in data:
        # linkedusers1 = data["linkedlistchangecontent"]["linkedusers"] #提取用户列表
        # elif "leavecontent" in data:
        # linkedusers1 = data["leavecontent"]["linkedusers"]
        # #linkedusers = data.get("linkedlistchangecontent", {}).get("linkedusers", [])
        # #print(linkedusers1)
        # for i, user_info in enumerate(linkedusers1):
        # user = user_info["user"]
        # play_key = f"play{i + 1}"
        # pk_user_info[play_key] = {
        # "id": user["id"],
        # "nickname": user["nickname"]
        # }
        # print(pk_user_info)
        # self.send_data.emit(pk_user_info)
        # except Exception as e:
        # logging.error(f"解析pk成员数据出错: {e}")
        # print(f"解析pk成员数据出错: {e}")
        # return data
        # print(f"linkMessage：{data}")

    def WebcastLinkMicBattleMethod(self, data):
        linkMicBattle = LinkMicBattle()
        linkMicBattle.ParseFromString(data)
        data = json_format.MessageToDict(
            linkMicBattle, preserving_proto_field_name=True
        )

    def WebcastLinkMicBattleFinishMethod(self, data):
        linkMicBattleFinish = LinkMicBattleFinish()
        linkMicBattleFinish.ParseFromString(data)
        data = json_format.MessageToDict(
            linkMicBattleFinish, preserving_proto_field_name=True
        )

    def WebcastLinkmicTeamfightScoreMessage(self, data):
        linkmicTeamfightScoreMessage = LinkmicTeamfightScoreMessage()
        linkmicTeamfightScoreMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkmicTeamfightScoreMessage, preserving_proto_field_name=True
        )

    ##8个
    def WebcastLinkmicTeamfightMessage(self, data):
        linkmicTeamfightMessage = LinkmicTeamfightMessage()
        linkmicTeamfightMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkmicTeamfightMessage, preserving_proto_field_name=True
        )

    def WebcastLinkmicOrderSingMessage(self, data):
        linkmicOrderSingMessage = LinkmicOrderSingMessage()
        linkmicOrderSingMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkmicOrderSingMessage, preserving_proto_field_name=True
        )

    def WebcastLinkmicOrderSingScoreMessage(self, data):
        linkmicOrderSingScoreMessage = LinkmicOrderSingScoreMessage()
        linkmicOrderSingScoreMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkmicOrderSingScoreMessage, preserving_proto_field_name=True
        )

    def WebcastLinkmicProfitMessage(self, data):
        linkmicProfitMessage = LinkmicProfitMessage()
        linkmicProfitMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkmicProfitMessage, preserving_proto_field_name=True
        )

        # PK的分数，

    def WebcastLinkMicMethod(self, data):
        webcastLinkMicMethod = LinkMicMethod()
        webcastLinkMicMethod.ParseFromString(data)
        data = json_format.MessageToDict(
            webcastLinkMicMethod, preserving_proto_field_name=True
        )
        try:
            pk_score_info = {
                "msg_info": "pk_score",
            }
            for user in data["userscores"]:
                pk_score_info[user["userid"]] = user["score"]
            pk_score_info["channelid"] = data["channelid"]
            pk_score_info["createtime"] = data["common"]["createtime"]
            # print(pk_score_info)

            self.send_data.emit(pk_score_info)
        except Exception as e:
            logging.error(f"解析pk成员数据出错: {e}")
            print(f"解析pk成员数据出错: {e}")
        return data

    def WebcastLinkMicArmiesMethod(self, data):
        linkMicArmies = LinkMicArmies()
        linkMicArmies.ParseFromString(data)
        data = json_format.MessageToDict(
            linkMicArmies, preserving_proto_field_name=True
        )

    def WebcastGuestBattleMessage(self, data):
        guestBattleMessage = GuestBattleMessage()
        guestBattleMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            guestBattleMessage, preserving_proto_field_name=True
        )

    def WebcastGuestBattleScoreMessage(self, data):
        guestBattleScoreMessage = GuestBattleScoreMessage()
        guestBattleScoreMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            guestBattleScoreMessage, preserving_proto_field_name=True
        )

    def WebcastLinkSettingNotifyMessage(self, data):
        linkSettingNotifyMessage = LinkSettingNotifyMessage()
        linkSettingNotifyMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            linkSettingNotifyMessage, preserving_proto_field_name=True
        )

    # 粉丝团信息
    def unPackWebcastUpdateFanTicketMessage(self, data):
        updateFanTicketMessage = UpdateFanTicketMessage()
        updateFanTicketMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            updateFanTicketMessage, preserving_proto_field_name=True
        )

        return data

    # 直播间信息统计
    def unPackWebcastRoomUserSeqMessage(self, data):
        roomUserSeqMessage = RoomUserSeqMessage()
        roomUserSeqMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            roomUserSeqMessage, preserving_proto_field_name=True
        )
        try:
            current_user = data["total"]
            total_user = data["totalUser"]
            self.roominfo_single.emit(current_user, total_user)

            # self.new_update_info.emit(current_user, total_user)
        except Exception as e:
            logging.error(f"解析直播间成员数据出错: {e}")
            print(f"解析直播间成员数据出错: {e}")
        return data

    # 关注消息
    def unPackWebcastSocialMessage(self, data):
        socialMessage = SocialMessage()
        socialMessage.ParseFromString(data)
        data = json_format.MessageToDict(
            socialMessage, preserving_proto_field_name=True
        )
        try:
            # user = data['user']['nickName']
            current_time = datetime.now().strftime("%H:%M:%S")
            user = data.get("user", {}).get("nickName", "神秘人xxx")
            # user_image_url = data['user']['AvatarThumb']['urlListList'][0]

            #social_message = (f'【关注】  <span style="color: red;">{user}</span>  关注了主播')
            social_message = f"""
<head><body style=" font-family:'Microsoft YaHei UI'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:20px;">
<span style=" vertical-align:middle;">[{current_time}]</span>
<span style=" vertical-align:middle; color:red;">【关注】</span>
<span style=" font-weight:400; color:black; vertical-align:middle;">{user}</span>
&nbsp;&nbsp;&nbsp;</span>
</p></body></head>
"""
            self.social_single.emit(social_message)
        #     self.new_update_gift.emit(social_message)
        except Exception as e:
            logging.error(f"解析直播间成员数据出错: {e}")
            print(f"解析直播间成员数据出错: {e}")
        return data

    # 普通消息
    def unPackWebcastChatMessage(self, data):
        chatMessage = ChatMessage()
        chatMessage.ParseFromString(data)
        # {"common": {"method": "WebcastChatMessage", "msgId": "7337700206451266611", "roomId": "7337673736771996442", "isShowMsg": true, "priorityScore": "31000"}, "user": {"id": "79473110627", "shortId": "148835245", "nickName": "Mr.韩较瘦", "gender": 1, "Level": 1, "AvatarThumb": {"urlListList": ["https://p26.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_ooAuBOEgN5A85DaoC79KFgblALnVACAIeAslfB.jpeg?from=3067671334"]}, "BadgeImageList": [{"urlListList": ["http://p3-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_17.png~tplv-obj.image"], "height": "16", "width": "32", "imageType": 1, "content": {"level": "17", "alternativeText": "荣誉等级17级勋章"}}], "FollowInfo": {"followingCount": "312", "followerCount": "753", "followStatus": "1", "followerCountStr": "0", "followingCountStr": "0"}, "displayId": "hyangWT", "secUid": "MS4wLjABAAAAF5Pc-yqHRijV5dMJPUomWwZGO37R7P0XBloLyCGK360"}, "content": "起码换衣服了[呲牙][呲牙][呲牙]", "giftImage": {"urlListList": ["\nVhttp://p3-webcast.douyinpic.com/img/webcast/userlabel_new_send_gift.png~tplv-obj.image*\u0007#F0F0F0"], "width": "50"}, "eventTime": "1708441463"}
        data = json_format.MessageToDict(chatMessage, preserving_proto_field_name=True)
        try:
            # user = data['user']['nickName']
            user = data.get("user", {}).get("nickName", "神秘人xxx")
            content = data["content"]
            pay_level = (
                data.get("user", {})
                .get("BadgeImageList", [{}])[0]
                .get("content", {})
                .get("level", "1")
            )
            # chat_message = f'{user} {content}'
            current_time = datetime.now().strftime("%H:%M:%S")
            if "[" in content and "]" in content:
                content = self.replace_emojis(content)
                # for emoji, filename in emoji_mapping.items():
                # local_path = os.path.join(filename)
                # if os.path.exists(local_path):
                # # 替换为本地表情包路径
                # content = content.replace(emoji, f'<img src="{local_path}" alt="{emoji}" style="vertical-align: middle;">')
            self.chat_single.emit(
                f"""
<head><body style=" font-family:'Microsoft YaHei UI'; font-size:11pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:20px;">
<span style=" vertical-align:middle;">[{current_time}]</span>
<img src="src/pic/level/level_v{pay_level}.png" width="36" height="18" style="vertical-align: middle;" />
<span style=" font-weight:500; color:#8ce7ff; vertical-align:middle;">{user} &nbsp;&nbsp;&nbsp;</span>
<span style=" vertical-align:middle; color:white;">{content}</span>
</p></body></head>
"""
            )
            # chat_message = f'<span style="color: blue;">{user}</span>：<span style="color: red;"> {content}</span>'
            # self.chat_single.emit(chat_message)
        except Exception as e:
            print(f"解析弹幕数据出错: {e}")
        return data

    # 礼物消息
    def unPackWebcastGiftMessage(self, data):
        giftMessage = GiftMessage()
        giftMessage.ParseFromString(data)
        data = json_format.MessageToDict(giftMessage, preserving_proto_field_name=True)
        # print(data)
        try:
            current_time = datetime.now().strftime("%H:%M:%S")
            gift_name = data.get("gift", {}).get("name", "未知礼物")
            nick_name = data.get("user", {}).get("nickName", "神秘人xxx")
            gift_diamond = data.get("gift", {}).get("diamondCount", "0")
            gift_effectid = data.get("gift", {}).get("primaryEffectId", "0")
            #gift_message = f'【礼物】  <span style="color: blue;">{nick_name}</span> <span style="color: red;"> {gift_name}</span> '
            
            gift_message = f"""
<head><body style=" font-family:'Microsoft YaHei UI'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:20px;">
<span style=" vertical-align:middle;">[{current_time}]</span>
<span style=" vertical-align:middle; color:#AF00FF;">【礼物】</span>
<span style=" font-weight:400; color:black; vertical-align:middle;">{nick_name}</span>
&nbsp;&nbsp;&nbsp;</span>
<span style=" vertical-align:middle; color:#1CA155;">{gift_name}</span>
</p></body></head>
"""
            self.gift_single.emit(gift_message)
            gift_info = {
                "msg_info": "gift_msg",
                "nick_name": nick_name,
                "gift_name": gift_name,
                "gift_diamond": gift_diamond,
                "gift_effectid": gift_effectid,
            }

            self.send_data.emit(gift_info)

        except Exception as e:
            logging.error(f"解析礼物数据出错: {e}")
            print(f"解析礼物数据出错: {e}")
        return data

    # xx成员进入直播间消息
    def unPackWebcastMemberMessage(self, data):
        memberMessage = MemberMessage()
        memberMessage.ParseFromString(data)
        # {"common": {"method": "WebcastLikeMessage", "msgId": "7337701414133872896", "roomId": "7337673736771996442", "isShowMsg": true, "anchorFoldType": "1", "anchorFoldTypeV2": "1"}, "count": "12", "total": "32024", "user": {"id": "93321611634", "shortId": "1462928073", "nickName": "小小银行", "AvatarThumb": {"urlListList": ["https://p11.douyinpic.com/aweme/100x100/aweme-avatar/dd225f7aa9d3864713eb949171860202.jpeg?from=3067671334", "https://p26.douyinpic.com/aweme/100x100/aweme-avatar/dd225f7aa9d3864713eb949171860202.jpeg?from=3067671334", "https://p3.douyinpic.com/aweme/100x100/aweme-avatar/dd225f7aa9d3864713eb949171860202.jpeg?from=3067671334"], "uri": "100x100/aweme-avatar/dd225f7aa9d3864713eb949171860202"}, "BadgeImageList": [{"urlListList": ["http://p3-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_13.png~tplv-obj.image", "http://p6-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_13.png~tplv-obj.image", "http://p11-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_13.png~tplv-obj.image"], "uri": "webcast/new_user_grade_level_v1_13.png", "height": "16", "width": "32", "imageType": 1, "content": {"level": "13", "alternativeText": "荣誉等级13级勋章"}}], "FollowInfo": {"followingCount": "1353", "followerCount": "64", "followerCountStr": "64", "followingCountStr": "1353"}, "displayId": "1462928073", "secUid": "MS4wLjABAAAACTY1PBESEfJSc8cjTQmXVzmbHDb6Rvt8sCs4EeKH7S4"}, "displayControlInfo": {"showIcons": true}}
        data = json_format.MessageToDict(
            memberMessage, preserving_proto_field_name=True
        )
        # 直播间人数统计
        try:
            # user = data['user']['nickName']
            current_time = datetime.now().strftime("%H:%M:%S")
            user = data.get("user", {}).get("nickName", "神秘人xxx")

            #enter_message = f'<span style="color: red;">{user}</span>  进入'
            enter_message = f"""
<head><body style=" font-family:'Microsoft YaHei UI'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:20px;">
<span style=" vertical-align:middle;">[{current_time}]</span>
<span style=" vertical-align:middle; color:black;">【进入】 </span>
<span style=" font-weight:400; color:red; vertical-align:middle;">{user}</span>
</p></body></head>
"""
            self.enter_single.emit(enter_message)
            level = (
                data.get("user", {})
                .get("BadgeImageList", [{}])[0]
                .get("content", {})
                .get("level", "0")
            )
            user_info = {"msg_info": "user_msg", "nick_name": user, "pay_level": level}

            self.send_data.emit(user_info)

        except Exception as e:
            logging.error(f"解析直播间成员数据出错: {e}")
            print(f"解析直播间成员数据出错: {e}")
        return data

    # 点赞
    def unPackWebcastLikeMessage(self, data):
        likeMessage = LikeMessage()
        likeMessage.ParseFromString(data)
        # {"common": {"method": "WebcastLikeMessage", "msgId": "7337700299043597321", "roomId": "7337673736771996442", "isShowMsg": true, "anchorFoldType": "1", "anchorFoldTypeV2": "1"}, "count": "9", "total": "31557", "user": {"id": "71317272863", "shortId": "87688073", "nickName": "柳轻风", "gender": 2, "Level": 1, "AvatarThumb": {"urlListList": ["https://p3.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_facde4e8282f4cd28d8404f423d51251.jpeg?from=3067671334", "https://p6.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_facde4e8282f4cd28d8404f423d51251.jpeg?from=3067671334", "https://p26.douyinpic.com/aweme/100x100/aweme-avatar/tos-cn-i-0813_facde4e8282f4cd28d8404f423d51251.jpeg?from=3067671334"], "uri": "100x100/aweme-avatar/tos-cn-i-0813_facde4e8282f4cd28d8404f423d51251"}, "BadgeImageList": [{"urlListList": ["http://p3-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_9.png~tplv-obj.image", "http://p6-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_9.png~tplv-obj.image", "http://p11-webcast.douyinpic.com/img/webcast/new_user_grade_level_v1_9.png~tplv-obj.image"], "uri": "webcast/new_user_grade_level_v1_9.png", "height": "16", "width": "32", "imageType": 1, "content": {"level": "9", "alternativeText": "荣誉等级9级勋章"}}], "FollowInfo": {"followingCount": "426", "followerCount": "371", "followerCountStr": "371", "followingCountStr": "426"}, "displayId": "87688073", "secUid": "MS4wLjABAAAA4jZlTUi2tD5tTh1GT9mc_pJs34XDPNeqIOKFF_ho-4A"}, "displayControlInfo": {"showIcons": true}}
        data = json_format.MessageToDict(likeMessage, preserving_proto_field_name=True)
        # like_num = int(data["total"])
        try:
            # user = data['user']['nickName']
            current_time = datetime.now().strftime("%H:%M:%S")
            user = data.get("user", {}).get("nickName", "神秘人xxx")
            count = data["count"]
            total = data["total"]
            #like_message = f'【点赞】  <span style="color: blue;">{user}</span> <span style="color: red;"> {count}</span> '
            
            like_message = f"""
<head><body style=" font-family:'Microsoft YaHei UI'; font-size:9pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:20px;">
<span style=" vertical-align:middle;">[{current_time}]</span>
<span style=" vertical-align:middle; color:#315984;">【点赞】</span>
<span style=" font-weight:400; color:black; vertical-align:middle;">{user}</span>
&nbsp;&nbsp;&nbsp;</span>
<span style=" vertical-align:middle; color:#FF0000;">{count}</span>
</p></body></head>
"""
            self.like_single.emit(like_message)
        except Exception as e:
            logging.error(f"解析点赞数据出错: {e}")
        return data

    # 解析WebcastMatchAgainstScoreMessage消息包体
    def unPackMatchAgainstScoreMessage(self, data):
        matchAgainstScoreMessage = MatchAgainstScoreMessage()
        matchAgainstScoreMessage.ParseFromString(data)
        data = json_format.MessageToDict(matchAgainstScoreMessage(data))
        data = json_format.MessageToDict(
            matchAgainstScoreMessage, preserving_proto_field_name=True
        )
        # print(f"MatchAgainstScoreMessage：{data}")
        return data

    def replace_emojis(self, content, emoji_mapping=emoji_mapping):
        for emoji, filename in emoji_mapping.items():
            local_path = os.path.join(filename)
            if os.path.exists(local_path):
                # 替换为本地表情包路径
                # content = content.replace(emoji, f'<img src="{local_path}" alt="{emoji}" width="18" height="18" style="vertical-align: middle;>')
                content = re.sub(
                    re.escape(emoji),
                    f'<img src="{local_path}" alt="{emoji}" width="18" height="18" style="vertical-align: middle;">',
                    content,
                )
            else:
                print(f"警告: 未找到表情包文件 {local_path}")
        return content

    # 发送Ack请求
    def sendAck(self, ws, logId, internalExt):
        obj = PushFrame()
        obj.payloadType = "ack"
        obj.logId = logId
        obj.payloadType = internalExt
        data = obj.SerializeToString()
        ws.send(data, websocket.ABNF.OPCODE_BINARY)

    def onError(self, ws, error):
        logging.error(
            "[onError] [webSocket Error事件] [房间Id：" + self.liveRoomId + "]"
        )

    def onClose(self, ws, close_status_code=None, close_reason=None):
        self.is_connected = False
        print(f"{self.liveRoomId} 断开连接！")

    def onOpen(self, ws):
        # self.onPing(ws)
        self.is_connected = True
        _thread.start_new_thread(self.onPing, (ws,))
        print(f"{self.liveRoomId} 建立连接！")

    def onPing(self, ws):
        while self.is_connected:
            obj = PushFrame()
            obj.payloadType = "hb"
            data = obj.SerializeToString()
            self.ws.send(data, websocket.ABNF.OPCODE_BINARY)
            # print("发送ping数据")
            time.sleep(10)

    def close_connection(self):  # 关闭ws连接
        if self.ws:
            self.ws.close()


class auto_reply_message(QThread):
    reply_info_single = pyqtSignal(str)

    def __init__(self, mediator, liveRoomId, cookie, parent=None):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.liveRoomId = liveRoomId
        self.user_cookies = cookie
        self.mediator_1 = mediator
        self.mediator_1.data_received.connect(
            self.handle_data, Qt.ConnectionType.QueuedConnection
        )

    @pyqtSlot(str)
    def handle_data(self, msg):
        # print(f"运行到自动回复消息：{msg}")
        if self.stop_thread == False:
            input_text = msg
            url = "https://live.douyin.com/webcast/room/chat/"
            params = {
                "aid": "6383",
                "app_name": "douyin_web",
                "live_id": "1",
                "device_platform": "web",
                "language": "zh-CN",
                "enter_from": "web_search",
                "cookie_enabled": "true",
                "screen_width": "2560",
                "screen_height": "1440",
                "browser_language": "zh-CN",
                "browser_platform": "Win32",
                "browser_name": "Chrome",
                "browser_version": "129.0.0.0",
                "room_id": self.liveRoomId,
                "content": input_text,
                "type": "0",
                "msToken": "y8dCOVYoEVUbEL9zp5ehSKiLSkLzt2g7aK05KRx5IUjaTCCB5eALvfOoyCVkr5QjBsg1sZ1USvwfKCA8k7rI2ZDpCD9Re_yalT9qIP3FCl7tU5IRmhBdrrZGmeJIzSEG-Rqc7XYGfKezVhtYvuJcJ3sikCz3wuuYVYGzikl5eDOoxIN7FScjiGE=",
            }

            headers = {
                "accept": "application/json, text/plain, */*",
                "accept-language": "zh-CN,zh;q=0.9",
                "priority": "u=1, i",
                "referer": "https://live.douyin.com/993521427634?column_type=single&is_aweme_tied=1&search_id=2024101816245909BA2F00181A22054D4F&search_result_id=7427021749050543423",
                "sec-ch-ua": '"Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
                "sec-ch-ua-mobile": "?0",
                "sec-ch-ua-platform": '"Windows"',
                "sec-fetch-dest": "empty",
                "sec-fetch-mode": "cors",
                "sec-fetch-site": "same-origin",
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
            }

            uri = urlencode(params)
            user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
            # 创建 BogusCreator 实例
            bc = a_bus.BogusCreator()
            # 使用提供的 uri 和 user_agent 创建 bogus 请求
            bogus_request = bc.create_bogus(uri, user_agent)
            params["a_bogus"] = bogus_request
            response = requests.get(
                url, params=params, headers=headers, cookies=self.user_cookies
            )
            if response.status_code == 200:
                # message = f'【发送成功】 {input_text}'
                self.reply_info_single.emit(
                    f"""
                </style></head><body style=" font-family:'Microsoft YaHei UI'; font-size:10pt; font-weight:400; font-style:normal;">
                <span style="color: blue">[回复成功] </span><span style="color: black">{input_text}</span>"""
                )
                # self.new_update_myinfo.emit(message)
                # print(f"已发送： {input_text}")
            else:
                # message = f'【发送失败】 {input_text}'
                self.reply_info_single.emit(
                    f"""
                </style></head><body style=" font-family:'Microsoft YaHei UI'; font-size:10pt; font-weight:400; font-style:normal;">
                <span style="color: red">[回复失败] </span><span style="color: black">{input_text}</span>"""
                )
                # self.new_update_myinfo.emit(message)
                # print("发送失败")


class auto_like(QThread):
    close_auto_like_single = pyqtSignal()
    auto_like_message = pyqtSignal(str)

    def __init__(self, liveRoomId, cookie, like_num, parent=None):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.liveRoomId = liveRoomId
        self.user_cookies = cookie
        self.like_num = like_num
        print(self.like_num)

    def run(self):
        if self.stop_thread == False:
            self.like_action()
        else:
            self.close_auto_like_single.emit()

    def like_action(self):
        url = "https://live.douyin.com/webcast/room/like/"
        # uri = f'aid=6383&app_name=douyin_web&live_id=1&device_platform=web&language=zh-CN&enter_from=page_refresh&cookie_enabled=true&screen_width=2560&screen_height=1440&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=130.0.0.0&room_id=' + self.liveRoomId + '&count=10'
        params = {
            "aid": "6383",
            "app_name": "douyin_web",
            "live_id": "1",
            "device_platform": "web",
            "language": "zh-CN",
            "enter_from": "web_search",
            "cookie_enabled": "true",
            "screen_width": "2560",
            "screen_height": "1440",
            "browser_language": "zh-CN",
            "browser_platform": "Win32",
            "browser_name": "Chrome",
            "browser_version": "130.0.0.0",
            "room_id": self.liveRoomId,
            "count": "11",
            "msToken": "y8dCOVYoEVUbEL9zp5ehSKiLSkLzt2g7aK05KRx5IUjaTCCB5eALvfOoyCVkr5QjBsg1sZ1USvwfKCA8k7rI2ZDpCD9Re_yalT9qIP3FCl7tU5IRmhBdrrZGmeJIzSEG-Rqc7XYGfKezVhtYvuJcJ3sikCz3wuuYVYGzikl5eDOoxIN7FScjiGE=",
        }
        headers = {
            "accept": "application/json, text/plain, */*",
            "accept-language": "zh-CN,zh;q=0.9",
            "origin": "https://www.douyin.com",
            "priority": "u=1, i",
            "referer": "https://www.douyin.com/",
            "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "Windows",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
            "x-secsdk-csrf-token": "0001000000017f17681433006de03c3da4c5274875b02f741c58d9b03497b76eed4f2340c4211808b10055eb6810",
        }
        # print(headers)
        user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        uri = urlencode(params)
        bc = a_bus.BogusCreator()
        bogus_request = bc.create_bogus(uri, user_agent)
        params["a_bogus"] = bogus_request
        while self.like_num > 0:

            response = requests.post(
                url, params=params, headers=headers, cookies=self.user_cookies
            )
            print(response.text)
            if self.stop_thread == True:
                self.close_auto_like_single.emit()
                break
            elif response.status_code == 200:
                if "手速" in response.text:
                    self.auto_like_message.emit("该时段已经点满了！")
                    self.stop_thread == True
                    self.close_auto_like_single.emit()
                    break
                self.like_num -= 11

                self.auto_like_message.emit("成功点赞11次")
                time.sleep(4)
            elif response.status_code != 200:
                self.auto_like_message.emit("请求出错了！")
                self.close_auto_like_single.emit()
        self.close_auto_like_single.emit()


class wss_info(QThread):
    user_list_single = pyqtSignal(str)
    gift_list_single = pyqtSignal(str)
    reply_message_single = pyqtSignal(str)
    pk_user_single = pyqtSignal(int)
    pk_score_single = pyqtSignal(dict)
    send_msg = pyqtSignal(str)
    play_gift_effect = pyqtSignal(str)

    def __init__(self, mediator, mediator_1, parent=None):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.mediator = mediator
        self.mediator_1 = mediator_1
        self.gift_value_value = 200
        self.consumption_level_value = 35
        self.reply_setting_pay_level = 99999
        self.reply_setting_fan_level = 99999
        self.reply_setting_gift_vaule = 99999
        self.reply_setting_welcome = "欢迎欢迎[鼓掌][鼓掌][鼓掌]"
        self.reply_setting_thank = "感谢大哥的礼物支持！"

        self.user_info_dict = {}
        self.pk_user_info = {}
        self.score_info = {}
        self.gift_effectid = ""
        self.gift_effect_list = {}
        self.channelid = ""
        self.mediator.data_received.connect(
            self.handle_data, Qt.ConnectionType.QueuedConnection
        )
        self.send_msg.connect(
            mediator_1.forward_data, Qt.ConnectionType.QueuedConnection
        )

        config_file_path = os.path.join(os.getcwd(), "effect_item.json")

        if os.path.exists(config_file_path):
            with open(config_file_path, "r") as f:
                self.gift_effect_list = json.load(f)
                # print(self.gift_effecti_list)

    @pyqtSlot(dict)
    def handle_data(self, msg):
        # print(f"成功接收：{msg}")
        # print(self.gift_value_value)
        if self.stop_thread == False:
            info_msg = msg.get("msg_info")
            # print(info_msg)
            # 礼物相关     "gift_effectid": gift_effectid
            if info_msg == "gift_msg":
                nick_name = msg.get("nick_name")
                gift_name = msg.get("gift_name")
                gift_diamond = msg.get("gift_diamond")
                self.gift_effectid = msg.get("gift_effectid")
                if gift_diamond >= self.gift_value_value:
                    # self.gift_list_single.emit(f"{nick_name}  {gift_name}   {gift_diamond}")
                    self.gift_list_single.emit(
                        f"""
</style></head><body style=" font-family:'Microsoft YaHei UI'; font-size:10pt; font-weight:400; font-style:normal;">
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; vertical-align:middle;">{nick_name}   </span><span style=" font-size:10pt; vertical-align:middle; color:#AF00FF;">&nbsp;&nbsp;{gift_name}   </span><span style=" font-size:10pt; vertical-align:middle;">&nbsp;&nbsp;{gift_diamond}</span><span style=" font-size:10pt;"> </span></p></body></html>
"""
                    )
                    if self.gift_effectid in self.gift_effect_list.keys():
                        url = self.gift_effect_list[self.gift_effectid]
                        self.play_gift_effect.emit(url)  # 发送礼物特效
                    if gift_diamond >= int(self.reply_setting_gift_vaule):
                        # self.reply_message_single.emit(f'@{nick_name} {self.reply_setting_thank}')
                        self.send_msg.emit(f"@{nick_name} {self.reply_setting_thank}")
                elif gift_diamond >= int(self.reply_setting_gift_vaule):
                    # self.reply_message_single.emit(f'@{nick_name} {self.reply_setting_thank}')  #高等级相关
                    self.send_msg.emit(f"@{nick_name} {self.reply_setting_thank}")
            elif info_msg == "user_msg":
                nick_name = msg.get("nick_name")
                pay_level = int(msg.get("pay_level"))
                if pay_level >= self.consumption_level_value:
                    # self.user_list_single.emit(f'<img src="src/pic/level/level_v{pay_level}.png" width="30" height="15" style="display:inline-block; vertical-align:middle;"> <span style="display:inline-block; vertical-align:middle;">{nick_name}</span>')
                    self.user_list_single.emit(
                        f"""
</style></head><body style="font-family:'Microsoft YaHei UI'; font-size:12pt; font-weight:400; font-style:normal;">
<p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">
    <img src="src/pic/level/level_v{pay_level}.png" width="34" height="17" style="vertical-align: middle;" />
    <span style="vertical-align:middle;">{nick_name}</span>
</p></body></html>
"""
                    )
                    if pay_level >= self.reply_setting_pay_level:
                        # self.reply_message_single.emit(f'@{nick_name} {self.reply_setting_welcome}')
                        self.send_msg.emit(f"@{nick_name} {self.reply_setting_welcome}")
                elif pay_level >= self.reply_setting_pay_level:
                    # self.reply_message_single.emit(f'@{nick_name} {self.reply_setting_welcome}')
                    self.send_msg.emit(f"@{nick_name} {self.reply_setting_welcome}")
                    #'<p>这是一张图片：</p><img src="image.jpg" width="200" height="200">'
            # 条件相关
            elif info_msg == "gift_value_value":
                self.gift_value_value = msg.get("value")
                print(f"gift_value_value：{self.gift_value_value}")
            elif info_msg == "consumption_level_value":
                self.consumption_level_value = msg.get("value")
                print(f"consumption_level_value：{self.consumption_level_value}")
            elif info_msg == "reply_setting":
                self.reply_setting_pay_level = msg.get("pay_level_value", 99999)
                self.reply_setting_fan_level = msg.get("fan_level_value", 99999)
                self.reply_setting_gift_vaule = msg.get("gift_value_value", 99999)
                self.reply_setting_welcome = msg.get(
                    "welcome_message", "欢迎欢迎[鼓掌][鼓掌][鼓掌]"
                )
                self.reply_setting_thank = msg.get(
                    "thank_message", "感谢礼物支持！！！"
                )
                print(
                    f"消费等级：{self.reply_setting_pay_level}，粉丝团等级：{self.reply_setting_fan_level}, 礼物价值：{self.reply_setting_gift_vaule}， 欢迎语：{self.reply_setting_welcome}，感谢语：{self.reply_setting_thank}"
                )
            # elif info_msg == "pk_user":
            # play_user_count = len([key for key in msg if key!= "msg_info"])  #统计用户数 pk_score
            # print(f"play_user_count: {play_user_count}")
            # self.pk_user_single.emit(play_user_count)
            # self.user_info_dict = {}
            # for i in range(1, play_user_count+1):
            # play_key = f"play{i}"
            # player_info = msg[play_key]
            # self.user_info_dict[f"play{i}_nickname"] = player_info['nickname']
            # self.user_info_dict[f"play{i}_id"] = player_info['id']
            # print(self.user_info_dict)

            elif info_msg == "pk_score":
                # print("运行到这里1")
                try:
                    if self.channelid == "":
                        self.channelid = msg.get("channelid")
                        uri = (
                            "https://live.douyin.com/webcast/linkmic/list/?aid=6383&app_name=douyin_web&live_id=1&device_platform=web&language=zh-CN&enter_from=page_refresh&cookie_enabled=true&screen_width=2560&screen_height=1440&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=130.0.0.0&"
                            + self.channelid
                            + "&channel_id="
                            + self.channelid
                            + "&offset=0&count=50&link_status=4&scene=1&request_source=audience_enter_room&msToken=6l0gdLOzJzKfjV1g8XjP-If3aQl6JyMSUVG8CDem42W6Gq6IgIifHqDakkPqFnMzjsKycAOMPWfpT96y2jI3f1W3EmyLaYtxdOz0lK3SamMZtB96DHE-CgqmqxrD8ulat5pp8Gw0uguA8YwFXKv5NiCeTg86YT-uaup4uidGdIjgAHyhgNjHjLU%3D"
                        )
                        user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"

                        # 创建 BogusCreator 实例
                        bc = a_bus.BogusCreator()
                        # print("运行到这里2")
                        # 使用提供的 uri 和 user_agent 创建 bogus 请求
                        bogus_request = bc.create_bogus(uri, user_agent)
                        uri += f"&a_bogus={bogus_request}"
                        res = requests.get(uri)
                        json_data = res.json()
                        # print(json_data)
                        self.pk_user_info = {}
                        # linkedusers = data.get("linkedlistchangecontent", {}).get("linkedusers", [])
                        linkedusers = json_data["data"]["user"]
                        for user_info in enumerate(linkedusers):
                            user = user_info["user"]
                            self.pk_user_info[user["id"]] = user["nickname"]
                    # print(self.pk_user_info)
                    self.score_info = {}
                    for key in self.pk_user_info:
                        if str(key) in msg:
                            self.score_info[self.pk_user_info[key]] = msg[str(key)]
                    # print(self.score_info)
                    # self.pk_score_single.emit(self.score_info)
                except Exception as e:
                    logging.error(f"pk_score: {e}")
                    print(f"pk_score: {e}")
            elif msg != {}:
                self.gift_effecti_list = msg
                print(f"礼物特效列表: {self.gift_effecti_list}")


class DataMediator(QObject):
    data_received = pyqtSignal(dict)  # 当数据到达时触发此信号

    @pyqtSlot(dict)
    def forward_data(self, data):
        self.data_received.emit(data)  # 转发数据
        # print(f"中介收到：{data}")


class DataMediator_1(QObject):
    data_received = pyqtSignal(str)  # 当数据到达时触发此信号

    @pyqtSlot(str)
    def forward_data(self, data):
        self.data_received.emit(data)  # 转发数据
        # print(f"中介收到：{data}")


#  线程
# ------------------------------------------------------------------------
#  界面234
class dialog1(QDialog):  # 自动回复设置界面
    send_data = pyqtSignal(dict)

    def __init__(self, mediator):
        super().__init__()

        self.dialog1 = Ui_Dialog()
        self.dialog1.setupUi(self)
        self.dialog1.pushButton.clicked.connect(self.save_settings)
        self.dialog1.pushButton_2.clicked.connect(self.import_settings)
        self.mediator = mediator
        self.send_data.connect(mediator.forward_data)
        self.dialog1.buttonBox.accepted.connect(self.get_values)
        self.import_settings()

    def run(self):
        self.import_settings()

    def get_values(self):
        # 提取消费等级相关设置
        #pay_level_comparison = self.dialog1.comboBox.currentText()
        pay_level_value = self.dialog1.spinBox.value()

        # 提取粉丝团等级相关设置
        #fan_level_comparison = self.dialog1.comboBox_2.currentText()
        fan_level_value = self.dialog1.spinBox_2.value()

        # 提取礼物价值相关设置
        #gift_value_comparison = self.dialog1.comboBox_4.currentText()
        gift_value_value = self.dialog1.spinBox_3.value()

        # 提取欢迎语和感谢语设置
        welcome_message = self.dialog1.lineEdit.text()
        thank_message = self.dialog1.lineEdit_2.text()
        # 构建配置信息字典
        reply_config = {
            "msg_info": "reply_setting",
            "pay_level_value": pay_level_value,
            "fan_level_value": fan_level_value,
            "gift_value_value": gift_value_value,
            "welcome_message": welcome_message,
            "thank_message": thank_message,
        }
        self.send_data.emit(reply_config)
        print(
            f"消费等级：{pay_level_value}，粉丝团等级：{fan_level_value}, 礼物价值：{gift_value_value}， 欢迎语：{welcome_message}，感谢语：{thank_message}"
        )

    def save_settings(self):
        # 提取消费等级相关设置
        pay_level_comparison = self.dialog1.comboBox.currentText()
        pay_level_value = self.dialog1.spinBox.value()

        # 提取粉丝团等级相关设置
        fan_level_comparison = self.dialog1.comboBox_2.currentText()
        fan_level_value = self.dialog1.spinBox_2.value()

        # 提取礼物价值相关设置
        gift_value_comparison = self.dialog1.comboBox_4.currentText()
        gift_value_value = self.dialog1.spinBox_3.value()

        # 提取欢迎语和感谢语设置
        welcome_message = self.dialog1.lineEdit.text()
        thank_message = self.dialog1.lineEdit_2.text()
        # 构建配置信息字典
        config_data = {
            "消费等级设置": {"比较符号": pay_level_comparison, "数值": pay_level_value},
            "粉丝团等级设置": {
                "比较符号": fan_level_comparison,
                "数值": fan_level_value,
            },
            "礼物价值设置": {
                "比较符号": gift_value_comparison,
                "数值": gift_value_value,
            },
            "欢迎语": welcome_message,
            "感谢语": thank_message,
        }

        # 定义配置文件保存路径，这里假设保存到当前目录下的config.json文件，你可以根据需求修改
        config_file_path = os.path.join(os.getcwd(), "config.json")
        with open(config_file_path, "w") as f:
            json.dump(config_data, f, indent=4)

        print("配置信息已保存到本地。")

    def import_settings(self):
        # 定义配置文件读取路径，与保存路径对应，这里假设为当前目录下的config.json
        config_file_path = os.path.join(os.getcwd(), "config.json")

        if os.path.exists(config_file_path):
            with open(config_file_path, "r") as f:
                config_data = json.load(f)

            # 填充消费等级相关设置
            pay_level_comparison = config_data["消费等级设置"]["比较符号"]
            pay_level_value = config_data["消费等级设置"]["数值"]
            self.dialog1.comboBox.setCurrentText(pay_level_comparison)
            self.dialog1.spinBox.setValue(pay_level_value)

            # 填充粉丝团等级相关设置
            fan_level_comparison = config_data["粉丝团等级设置"]["比较符号"]
            fan_level_value = config_data["粉丝团等级设置"]["数值"]
            self.dialog1.comboBox_2.setCurrentText(fan_level_comparison)
            self.dialog1.spinBox_2.setValue(fan_level_value)

            # 填充礼物价值相关设置
            gift_value_comparison = config_data["礼物价值设置"]["比较符号"]
            gift_value_value = config_data["礼物价值设置"]["数值"]
            self.dialog1.comboBox_4.setCurrentText(gift_value_comparison)
            self.dialog1.spinBox_3.setValue(gift_value_value)

            # 填充欢迎语和感谢语设置
            welcome_message = config_data["欢迎语"]
            thank_message = config_data["感谢语"]
            self.dialog1.lineEdit.setText(welcome_message)
            self.dialog1.lineEdit_2.setText(thank_message)

            print("配置信息已从本地导入。")
        else:
            print("配置文件不存在，请先保存配置信息。")


class dialog2(QDialog):
    send_data = pyqtSignal(dict)

    def __init__(self, mediator):
        super().__init__()

        self.dialog2 = Ui_Dialog2()
        self.dialog2.setupUi(self)
        self.mediator = mediator
        self.send_data.connect(mediator.forward_data)

        # 连接按钮的点击事件等操作可以在这里进行
        self.dialog2.buttonBox.accepted.connect(self.get_values)

    def get_values(self):
        # 获取消费等级相关设置
        global consumption_level_value
        consumption_level_comparison = self.dialog2.comboBox.currentText()
        consumption_level_value = self.dialog2.spinBox.value()
        level_list_value = {
            "msg_info": "consumption_level_value",
            "value": consumption_level_value,
        }
        self.send_data.emit(level_list_value)

        # 获取实时检测在直播间的勾选状态
        is_real_time_detecting = self.dialog2.checkBox.isChecked()

        print("消费等级设置：", consumption_level_comparison, consumption_level_value)
        print("实时检测在直播间的勾选状态：", is_real_time_detecting)


class dialog3(QDialog):
    send_data = pyqtSignal(dict)

    def __init__(self, mediator):
        super().__init__()

        self.dialog3 = Ui_Dialog3()
        self.dialog3.setupUi(self)

        # 连接按钮的点击事件等操作可以在这里进行

        self.mediator = mediator
        self.send_data.connect(mediator.forward_data)
        self.dialog3.buttonBox.accepted.connect(self.get_values)

    def get_values(self):
        # 获取礼物价值相关设置
        gift_value_comparison = self.dialog3.comboBox_4.currentText()
        gift_value_value = self.dialog3.spinBox_3.value()
        gift_list_value = {"msg_info": "gift_value_value", "value": gift_value_value}
        self.send_data.emit(gift_list_value)

        print("礼物价值设置：", gift_value_comparison, gift_value_value)


class dialog4(QDialog):

    def __init__(self, liveRoomId, cookie):
        super().__init__()

        self.dialog4 = Ui_Dialog4()
        self.dialog4.setupUi(self)
        self.liveRoomId = liveRoomId
        self.user_cookies = cookie
        self.query_ranklist()
        self.finished.connect(self.dialog_finished)

    def query_ranklist(self):
        try:
            self.thread_ranklist = ranklist(self.liveRoomId, self.user_cookies)
            # self.thread_ranklist.gift_list_single.connect(self._gift_list)
            self.thread_ranklist.ranklist_single.connect(
                self.display_ranklist, Qt.ConnectionType.QueuedConnection
            )
            # self.thread_ranklist.reply_message_single.connect(self.display_ranklist, Qt.ConnectionType.QueuedConnection)
            # self.thread_wss_info.pk_score_single.connect(self._pk_score)
            # self.update_myinfo_signal.emit("wss辅助线程 开启")
            self.thread_ranklist.start()
        except Exception as e:
            print(f"线程启动失败: {e}")

    def display_ranklist(self, msg):
        self.dialog4.textBrowser.setText(msg)

    def dialog_finished(self):
        try:
            if self.thread_ranklist:
                self.thread_ranklist.stop_thread = True
                self.thread_ranklist.quit()
                #self.thread_ranklist.wait()  #影响用户体验 ui延迟
        except Exception as e:
            print(f"ranklist线程关闭失败: {e}")


class dialog5(QDialog):
    send_data = pyqtSignal(dict)

    def __init__(self, mediator):
        super().__init__()

        self.dialog5 = Ui_Dialog5()
        self.dialog5.setupUi(self)
        self.gift_list = {}
        self.dialog5.pushButton.clicked.connect(
            lambda: self.save_gift_effect(self.gift_list)
        )
        self.dialog5.pushButton_2.clicked.connect(self.download_gift_effect)
        self.dialog5.pushButton_3.clicked.connect(self.search_gift_effect)
        self.list_widget = self.dialog5.listWidget_2
        # self.list_widget.setSizePolicy(Qt.SizePolicy.Expanding, Qt.SizePolicy.Expanding)
        # self.list_widget.setMinimumHeight(0)  # 允许最小高度为0，避免限制太死

        self.mediator = mediator
        self.send_data.connect(mediator.forward_data)

    def download_gift_effect(self):
        url = "https://live.douyin.com/webcast/assets/effects/?aid=6383"
        data = requests.get(url).json()
        # self.gift_list = data
        if "assets" in data["data"]:
            effect_list = data["data"]["assets"]
            for effect_item in effect_list:
                gift_effect_name = effect_item["name"]
                download_url = effect_item["resource_uri"]
                gift_effect_id = effect_item["id"]
                # print(gift_effect_name)
                self.gift_list[gift_effect_id] = download_url

                item = QListWidgetItem(self.list_widget)
                widget = GiftItem(gift_effect_name, download_url, gift_effect_id)
                item.setSizeHint(widget.sizeHint())
                self.list_widget.addItem(item)
                self.list_widget.setItemWidget(item, widget)

    @pyqtSlot()
    def search_gift_effect(self):
        search_text = self.dialog5.lineEdit.text().strip()
        for index in range(self.list_widget.count()):
            item = self.list_widget.item(index)
            widget = self.list_widget.itemWidget(item)
            if search_text.lower() in widget.name_label.text():
                # if search_text.lower() in widget.name_label.text.lower():  #加了.lower()后闪退！
                item.setHidden(False)
            else:
                item.setHidden(True)

    def save_gift_effect(self, data):
        if data != {}:
            config_file_path = os.path.join(os.getcwd(), "effect_item.json")
            with open(config_file_path, "w") as f:
                json.dump(data, f, indent=4)

            self.send_data.emit(self.gift_list)

            print("配置信息已保存到本地。")


class ranklist(QThread):
    ranklist_single = pyqtSignal(str)

    def __init__(self, liveRoomId, cookie, parent=None):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.liveRoomId = liveRoomId
        self.user_cookies = cookie

    def run(self):
        if self.stop_thread == False:
            self.query_ranklist()

    def query_ranklist(self):
        while self.stop_thread == False:
            url = "https://live.douyin.com/webcast/ranklist/audience/"
            params = {
                "aid": "6383",
                "app_name": "douyin_web",
                "live_id": "1",
                "device_platform": "web",
                "language": "zh-CN",
                "enter_from": "web_search",
                "cookie_enabled": "true",
                "screen_width": "2560",
                "screen_height": "1440",
                "browser_language": "zh-CN",
                "browser_platform": "Win32",
                "browser_name": "Chrome",
                "browser_version": "130.0.0.0",
                "webcast_sdk_version": "2450",
                "room_id": self.liveRoomId,
                "anchor_id": "1256074040581561",
                "sec_anchor_id": "MS4wLjABAAAA75aieqOhIRY3izxMFt6EnUmHvvJzBlSt51yaghQeJjPu-jlqHLqDekZrrxmyUQSU",
                "rank_type": "30",
                "msToken": "y8dCOVYoEVUbEL9zp5ehSKiLSkLzt2g7aK05KRx5IUjaTCCB5eALvfOoyCVkr5QjBsg1sZ1USvwfKCA8k7rI2ZDpCD9Re_yalT9qIP3FCl7tU5IRmhBdrrZGmeJIzSEG-Rqc7XYGfKezVhtYvuJcJ3sikCz3wuuYVYGzikl5eDOoxIN7FScjiGE=",
            }

            headers = {
                "accept": "application/json, text/plain, */*",
                "accept-language": "zh-CN,zh;q=0.9",
                "priority": "u=1, i",
                "referer": "https://live.douyin.com/993521427634?column_type=single&is_aweme_tied=1&search_id=2024101816245909BA2F00181A22054D4F&search_result_id=7427021749050543423",
                "sec-ch-ua": '"Chromium";v="130", "Google Chrome";v="130", "Not?A_Brand";v="99"',
                "sec-ch-ua-mobile": "?0",
                "sec-ch-ua-platform": '"Windows"',
                "sec-fetch-dest": "empty",
                "sec-fetch-mode": "cors",
                "sec-fetch-site": "same-origin",
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
            }

            uri = urlencode(params)
            user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
            # 创建 BogusCreator 实例
            bc = a_bus.BogusCreator()
            # 使用提供的 uri 和 user_agent 创建 bogus 请求
            bogus_request = bc.create_bogus(uri, user_agent)
            params["a_bogus"] = bogus_request
            response = requests.get(
                url, params=params, headers=headers, cookies=self.user_cookies
            )
            data = response.json()
            # print(data)
            try:
                if "data" in data and "ranks" in data["data"]:
                    ranks_list = data["data"]["ranks"]  # 提取用户列表
                    # print(ranks_list)
                    user_info_dict = {}
                    total_message = ""

                    for rank_item in ranks_list:
                        if "user" in rank_item:
                            html_fragment = ""
                            html_fragment_1 = ""
                            user_info = rank_item["user"]
                            nickname = user_info.get("nickname")
                            rank = rank_item.get("rank")
                            # score = rank_item.get("score")
                            pay_grade = user_info.get("pay_grade").get("level", "0")
                            fans_club = (
                                user_info.get("fans_club").get("data").get("level", "0")
                            )
                            url_list = user_info.get("avatar_thumb").get("url_list")[0]
                            # user_info_dict[rank] = {
                            # "nickname": nickname,
                            # "score": score,
                            # "pay_grade": pay_grade,
                            # "fans_club": fans_club,
                            # "avatar_url": url_list
                            # }
                            if pay_grade != 0:
                                html_fragment += f'<img src="src/pic/level/level_v{pay_grade}.png" width="32" height="16" style="vertical-align: middle;" />'
                            if fans_club != 0:
                                html_fragment += f'<img src="src/pic/fans/{fans_club}.png" width="20" height="16" style="vertical-align: middle;" />'
                            # if score != 0:
                            # html_fragment_1 = f'<span style="vertical-align:middle; color: #94C1FF;">{score}</span>'

                            message = f"""
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>用户信息展示</title>
            </head>
            <body style="font-family:'Microsoft YaHei UI'; font-size:12pt; font-weight:400; font-style:normal;">
                <p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height: 16px;">
                    <span style="vertical-align:middle;">{rank}&nbsp;&nbsp;</span>
                    {html_fragment}
                    <span style="vertical-align:middle;">{nickname}&nbsp;&nbsp;</span>
                    {html_fragment_1}
                    
                </p>
            </body>
            </html>
            """
                            total_message += message + "\n"
                    self.ranklist_single.emit(total_message)

                    # print(user_info_dict)

            except Exception as e:
                logging.error(f"解析pk成员数据出错: {e}")
                print(f"解析pk成员数据出错: {e}")
            if self.stop_thread == False:
                time.sleep(5)


class video_encode(QThread):  # 已使用aphla方法，此处无需调用

    def __init__(self, input_file, output_file, parent=None):  # 传进2个参数
        super().__init__(parent)
        self.stop_thread = False
        self.input_file = input_file
        self.output_file = output_file

    # self.run()

    def run(self):
        try:
            print("运行到try这里了")
            process = process_video(self.input_file, self.output_file)
        # 这里可以进一步添加代码来处理process的相关信号等，和原来在MainWindow中的逻辑类似
        except ValueError as e:
            print(f"处理视频出错: {e}")


class GiftItem(QWidget):

    play_effect_single = pyqtSignal(str)

    def __init__(self, name, url, id):
        super().__init__()
        layout = QHBoxLayout()

        # 设置布局的边距和间距，使各部件分布更合理且看起来更整齐
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(10)

        self.name_label = QLabel(name)
        self.name_label.setFixedWidth(140)
        layout.addWidget(self.name_label)

        self.url_label = QLabel(url)
        self.url_label.setFixedWidth(200)
        layout.addWidget(self.url_label)

        self.id_label = QLabel(str(id))
        # self.name_label.setFixedWidth(280)
        layout.addWidget(self.id_label)

        # 添加进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)  # 初始进度为0
        # self.name_label.setFixedWidth(280)
        layout.addWidget(self.progress_bar)

        # 添加下载按钮
        self.download_button = QPushButton("下载")
        # self.name_label.setFixedWidth(280)
        self.download_button.clicked.connect(lambda: self.start_download(url, name))
        layout.addWidget(self.download_button)

        # self.encode_effect = QPushButton('转码')
        # #self.name_label.setFixedWidth(280)
        # self.encode_effect.clicked.connect(lambda: self.start_encode(name))
        # layout.addWidget(self.encode_effect)

        self.preview_effect = QPushButton("预览")
        # #self.name_label.setFixedWidth(280)
        self.preview_effect.clicked.connect(lambda: window.gift_url_list(url))
        layout.addWidget(self.preview_effect)

        # try:
        # # 这里放置可能出现问题的代码，比如创建QCheckBox及相关布局操作等
        # self.display_effect = QCheckBox('显示特效')
        # layout.addWidget(self.display_effect)
        # except Exception as e:
        # print(f"出现异常: {e}")

        self.setLayout(layout)

    def start_download(self, download_url, name):
        """
        执行文件下载操作，并更新进度条展示下载进度
        """
        # 获取当前工作目录，你也可以指定其他具体的保存路径
        # 使用相对路径指定保存目录，这里假设要保存到当前工作目录下的downloads文件夹
        save_path = os.path.join(os.getcwd(), "downloads")
        if not os.path.exists(save_path):
            os.makedirs(save_path)  # 如果目录不存在，则创建它
        # file_name = download_url.split('/')[-1]
        file_name = name + ".zip"
        file_full_path = os.path.join(save_path, file_name)

        try:
            with requests.get(download_url, stream=True) as r:
                r.raise_for_status()  # 检查请求是否成功，若不成功则抛出异常
                total_size = int(
                    r.headers.get("content-length", 0)
                )  # 获取文件总大小（字节数）
                downloaded_size = 0
                with open(file_full_path, "wb") as f:
                    for chunk in r.iter_content(
                        chunk_size=8192
                    ):  # 分块读取下载内容，这里块大小设为8KB，可调整
                        if chunk:
                            f.write(chunk)
                            downloaded_size += len(chunk)
                            # 计算下载进度百分比，并更新进度条
                            progress_percentage = int(
                                downloaded_size / total_size * 100
                            )
                            self.progress_bar.setValue(progress_percentage)
        except requests.RequestException as e:
            print(f"下载出现网络相关异常: {e}")
        except OSError as e:
            print(f"文件保存出现异常，可能是磁盘问题等: {e}")
        except Exception as e:
            print(f"其他未知异常: {e}")

    def start_encode(self, gift_effect_name):
        print("开启解码进程")
        file_name = gift_effect_name + ".zip"
        new_folder_path = os.path.join(os.getcwd(), "Downloads", file_name)
        print(new_folder_path)
        if os.path.exists(new_folder_path):
            ex_folder_path = os.path.join("Downloads", f"{gift_effect_name}")
            os.makedirs(ex_folder_path, exist_ok=True)
            print("运行到这里了")
            with zipfile.ZipFile(new_folder_path, "r") as zip_ref:
                # 解压文件到Downloads文件夹下（可根据需求修改解压路径）
                zip_ref.extractall(ex_folder_path)
                print("解压完成")
                video_path = os.path.join(os.getcwd(), ex_folder_path, "output.mp4")
                print(video_path)
                video_name = gift_effect_name + ".webm"
                video_out_dir = os.path.join(os.getcwd(), "gift_effect")
                video_out_patch = os.path.join(video_out_dir, video_name)
                print(video_out_patch)
                os.makedirs(video_out_dir, exist_ok=True)

                # input_file = "your_input_video.mp4"
                # output_file = "your_output_video.webm"
                input_file = video_path
                output_file = video_out_patch
                # encode = encode_video.videoencode()
                print(input_file)
                print(output_file)

                # try:
                # print("运行到try这里了")
                # process = process_video(input_file, output_file)
                # # 这里可以进一步添加代码来处理process的相关信号等，和原来在MainWindow中的逻辑类似
                # except ValueError as e:
                # print(f"处理视频出错: {e}")

                self.thread_video_encode = video_encode(input_file, output_file)
                # self.thread_wss.total_info_single.connect(self.display_gift_user_reply, Qt.ConnectionType.QueuedConnection)  #传输字典
                # self.update_myinfo_signal.emit("准备启动弹幕线程")
                self.thread_video_encode.start()

class MediaWindow(QWidget):
    def __init__(self, adr):
        super().__init__()
        self.adr = adr
        print(adr)
        layout = QVBoxLayout()
        self._separate_window = QVideoWidget(self)
        self._separate_window.setWindowFlags(Qt.Tool)
        self._separate_window.resize(540, 768)        
        self.player_1 = QMediaPlayer(self)
        self.playlist1 = QMediaPlaylist(self.player_1)
        self.player_1.setPlaylist(self.playlist1)
        self.player_1.setVideoOutput(self._separate_window)

        media_content = QMediaContent(QUrl(self.adr))
        self.playlist1.addMedia(media_content)

        layout.addWidget(self._separate_window)
        self.setLayout(layout)
        self._separate_window.closeEvent = self.close_video_window 
        # 连接mediaStatusChanged信号，用于在视频状态变化时调整视频显示大小
        # self.player.mediaStatusChanged.connect(self.adjust_video_size)
        self._separate_window.show()
        
        self.player_1.play()
    def close_video_window(self, event):
        self.playlist1.clear()
        self.player_1.stop()
        window.live_stream(self.adr)
        del self._separate_window         
        event.accept()


class EmojiSelectorDialog(QDialog):
    def __init__(self, emoji_images, parent=None):
        super().__init__(parent)
        self.setWindowTitle("选择表情")
        self.setFixedSize(400, 300)  # 设置固定大小
        try:
            input_box_geometry = window.ui.textEdit.geometry()
            input_box_global_pos = window.ui.textEdit.mapToGlobal(QPoint(0, 0))
            #print(input_box_geometry)
            #print(input_box_global_pos)
            x = input_box_global_pos.x()
            #print(x)
            y = input_box_global_pos.y() + input_box_geometry.height()
                # 计算对话框的起始位置，使其位于输入框的正下方
            x = input_box_global_pos.x()
            y = input_box_global_pos.y() + input_box_geometry.height()
            #print(y)

            # # 确保对话框不会超出屏幕范围
            # screen_geometry = QApplication.desktop().screenGeometry(input_box)
            # if x + self.width() > screen_geometry.width():
                # x = screen_geometry.width() - self.width()
            
            # if y + self.height() > screen_geometry.height():
                # # 如果没有足够空间放在下方，则尝试放在上方
                # y = input_box_global_pos.y() - self.height()
                # if y < 0:  # 检查上方是否有足够的空间
                    # y = 0  # 如果没有，设置为屏幕顶部
            self.move(x, y)
            #self.show()
        except Exception as e:
            print(f"捕获位置出错: {e}")

        # 移除边框
        self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)

        # 移除外边距
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)  # 移除所有外边距

        self.model = QStandardItemModel()
        self.listView = QListView()
        self.listView.setIconSize(QSize(32, 32))  # 设置图标大小
        self.listView.setUniformItemSizes(True)  # 提高性能
        self.listView.setViewMode(QListView.IconMode)
        self.listView.setResizeMode(QListView.Adjust)

        if emoji_images:  # 确保列表不为空以避免后续操作中的错误
            for image_path in emoji_images:
                item = QStandardItem()
                pixmap = QPixmap(str(image_path)).scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation)  # 调整表情大小
                if not pixmap.isNull():  # 检查图片是否加载成功
                    item.setIcon(QIcon(pixmap))
                    item.setEditable(False)
                    self.model.appendRow(item)

            sample_pixmap = QPixmap(str(emoji_images[0])).scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            icon_size = sample_pixmap.size()
            spacing = QSize(8, 8)  # 设置间距

            grid_size = QSize(
                icon_size.width() + spacing.width(),
                icon_size.height() + spacing.height()
            )

            self.listView.setGridSize(grid_size)  # 设置网格大小

        self.listView.setModel(self.model)
        self.listView.clicked.connect(self.on_item_clicked)  # 连接点击事件

        layout.addWidget(self.listView)
        self.setLayout(layout)

        # 应用样式表以移除默认边框和其他不必要的样式
        self.setStyleSheet("""
            QDialog {
                background-color: white;
                border: none;
            }
            QListView::item {
                padding: 0px;
                margin: 0px;
            }
        """)
        # self.installEventFilter(self)

    # def eventFilter(self, obj, event):
        # print(f"事件类型: {event.type()}")  # 调试信息：打印事件类型
        
        # if event.type() == QEvent.MouseButtonPress:
            # print("运行到这里2")
            # mouse_event = event  # 强制转换为QMouseEvent，以便使用mouseEvent属性
            # global_pos = mouse_event.globalPos()
            
            # # 如果点击发生在对话框外部，则关闭对话框
            # if not self.geometry().contains(global_pos):
                # print("运行到这里3")
                # self.clickedOutside.emit()
                # return True
            
            # # 额外调试信息
            # print(f"鼠标点击位置: {global_pos}")
            # print(f"对话框几何位置: {self.geometry()}")
        
        # return super().eventFilter(obj, event)

    def on_item_clicked(self, index):
        try:
            self.selected_index = index.row()
            self.accept()  # 关闭对话框并返回结果
        except Exception as e:
            print(f"在处理表情点击事件时出现错误: {e}")


class WindowPositionTracker(QObject):
    position_changed = pyqtSignal(int, int)

    def __init__(self, target_widget):
        super().__init__()
        self.target_widget = target_widget
        self.target_widget.installEventFilter(self)

    def eventFilter(self, watched, event):
        if watched == self.target_widget and event.type() == QEvent.Move:
            # 获取相对于屏幕的位置
            global_pos = self.target_widget.mapToGlobal(self.target_widget.pos())
            x = global_pos.x()
            y = global_pos.y()
            self.position_changed.emit(x, y)
        return super().eventFilter(watched, event)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.setWindowIcon(QIcon('douyin.ico'))
    window.show()
    sys.exit(app.exec())
